> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/developer-guide/common-errors.md).

# Common errors

The failures that span more than one page — what you see, what it means, what to do.

Failures that appear in more than one place, collected. Each page also has its own symptom table for problems specific to it.

## Script compilation

| What you see                                                 | What it means                                                        | What to do                                                                                                                                                   |
| ------------------------------------------------------------ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `unable to resolve class org.openiam...` on save             | The class is not on the platform's classpath, or the import is wrong | Check the import against the tutorial for that script type. Compile locally first — [*Set up your environment*](/developer-guide/set-up-your-environment.md) |
| Compiles locally, fails on save                              | Local Groovy or JDK does not match the platform                      | Groovy 5.0.4, JDK 21                                                                                                                                         |
| `Could not resolve dependencies for org.openiam:...` locally | The repository is not configured, or the profile is not active       | Check `~/.m2/settings.xml`. `mvn -X compile` shows which repositories were tried                                                                             |
| The class is not found although the file is there            | The class name does not match the file name                          | `MemberOf_1.0.groovy` must declare `class MemberOf`                                                                                                          |

## Scripts that do not run

| What you see                          | What it means                                                           | What to do                                                                                          |
| ------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Nothing happens and there is no error | A batch script written as a class. Top-level statements never run       | Batch scripts are plain scripts, not classes — [*Batch scripts*](/developer-guide/batch-scripts.md) |
| A class-based script never runs       | Not referenced by name in the configuration it belongs to               | Check the synchronisation, policy map or reconciliation configuration                               |
| It ran once and never again           | Attached to a task that is disabled, or the situation stopped occurring | Check the scheduled task, or the reconciliation report                                              |

## Injected services

| What you see                                                | What it means                                                        | What to do                                                                          |
| ----------------------------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| An injected service is null at runtime                      | Injection resolves inside the platform's Spring context, not locally | Cannot be reproduced locally. Test on a deployment                                  |
| `NullPointerException` on a service call that looks correct | The response wrapper was not unwrapped                               | Add `.getValue()`                                                                   |
| `groovy.lang.MissingPropertyException: context`             | The `context` binding is not available in that script type           | Only batch scripts receive it as a binding. Class-based types use an injected field |

## Values reaching a target system

| What you see                                      | What it means                                       | What to do                                                                                                              |
| ------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Values accumulate instead of replacing            | The operation was not passed with the value         | Pass `diffObject.getStatus()` into the connector value — [*Policy map scripts*](/developer-guide/policy-map-scripts.md) |
| An attribute is never written                     | `isPerform` returns `false`                         | Log `diffObject.getStatus()` at the top of it                                                                           |
| An attribute is overwritten when it should not be | `isPerform` does not distinguish create from update | Gate on `AttributeOperationEnum.ADD`                                                                                    |

## Synchronisation

| What you see                              | What it means                                                  | What to do                                                                                          |
| ----------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Every row is skipped                      | The transformation is returning `SKIP`, usually from a `catch` | Log the exception. It is being swallowed                                                            |
| Objects created but fields empty          | Column names do not match the source                           | Log `rowObj.columnMap.keySet()` once and compare                                                    |
| Updates create duplicates                 | The id is cleared on update                                    | Guard the id reset with `isNewUser`                                                                 |
| An attribute is missing in transformation | Not declared in `getAttributes()`                              | Add it — [*Validation and attribute scripts*](/developer-guide/validation-and-attribute-scripts.md) |
| The run is very slow                      | Per-row lookups instead of the base class caches               | Use `rolesByName` and the other caches                                                              |

## The API

**Most API confusion comes from reading the wrong envelope.** Three exist, they are returned by different kinds of endpoint, and their field names do not overlap — [*API fundamentals*](/developer-guide/fundamentals.md) has the table.

| What you see                                         | What it means                                                                            | What to do                                                                                                                       |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| HTTP `200` with no `access_token`                    | The token request failed and the failure is in the body                                  | Read `error` and `error_description` — [*Tokens*](/developer-guide/tokens.md)                                                    |
| HTTP `200` but nothing was saved                     | The body's own `status` carries the outcome                                              | Branch on `status == 200` inside the body, not on the HTTP code                                                                  |
| `status` is a number, not `"success"`                | You are reading a state-changing endpoint                                                | Its `status` is an HTTP-style integer. There is no `"success"` value in that envelope                                            |
| `status` is missing entirely                         | You are reading a search or paged read                                                   | Results are in `beans`; failures in `error`                                                                                      |
| `errorCode` and `fieldMappings` are always null      | Those belong to the internal service envelope, which scripts see and REST callers do not | Read `errorList`; an entry's `validationError` names the field                                                                   |
| A save is refused with no clear reason               | A field failed validation                                                                | Read `errorList`                                                                                                                 |
| A search returns nothing although the data exists    | The body carried no criteria, so `emptySearchBean` is set                                | Add at least one criterion; paging alone is not a search                                                                         |
| HTTP `401` on a call that worked before              | The token expired, or the session behind it did                                          | Refresh it, and check `expired` against `session_expired` — [*Tokens*](/developer-guide/tokens.md)                               |
| HTTP `403` with a valid token                        | The client's scopes do not cover the path                                                | Widen the provider's scopes to what is needed                                                                                    |
| HTTP `405` on a provisioning call                    | The request used `PUT` or `GET`                                                          | Provisioning operations are `POST`, and the identifier goes in the body — [*Managing users*](/developer-guide/user-lifecycle.md) |
| `status: 401` with `ACCESS_DENIED`                   | The requester lacks an authorisation right the operation checks                          | Grant the right — [*Managing users*](/developer-guide/user-lifecycle.md)                                                         |
| A scheduled provisioning action never happens        | `performDataString` was not in the expected format, or `performNow` overrode it          | `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`, read as UTC                                                                                      |
| A user changed in OpenIAM but not in a target system | `skipProvisioningManagedSystemSet` named that system                                     | Remove it from the set                                                                                                           |
| A second user appears instead of an update           | `saveUser` was called without `id`                                                       | Include `id` to update; omitting it creates                                                                                      |

## When none of this fits

**Read the shipped scripts.** They are production code under `conf/iamscripts/`, and a working example of the pattern you are attempting usually exists.

**Then raise it with your OpenIAM account team**, with the script, the configuration it is attached to, and the log output around the failure.

## Related

* [*How scripting works*](/developer-guide/how-scripting-works.md)
* [*API fundamentals*](/developer-guide/fundamentals.md)
* [*Tokens*](/developer-guide/tokens.md)
* [*Managing users*](/developer-guide/user-lifecycle.md)

*Applies to OpenIAM 2026.8.1.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/developer-guide/common-errors.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
