# Monitoring Codes

Every monitoring code the Integration Toolkit emits, what it means, and what to do about it

{/* AUTOGENERATED — do not edit by hand.
    Source: erp-integration-api packages/erp-utils/src/monitoring/__snapshots__/monitoring-codes.json
    Regenerate: npm run update-monitoring-codes */}

# Monitoring Codes

Every monitoring event carries a **code** and a **level**. The code says what
happened; the level says how much you should care. Both are filterable in the
Integration Hub's [Monitoring tab](./overview.md) and through the events API.

There are 99 codes. You are most likely here because you saw one in a failed
event — find it below.

> **Tip: A code's level is fixed. That is what makes alert rules scoped to `_error_` or**
`_warning_` predictable — see [Alerting](./alerting.md#choosing-what-to-watch).

The interactive lane codes (`INTERACTIVE_*` and `CORRELATION_*`) are explained in
context, with when each is raised, in [Interactive Registration](../interactive-registration.md#monitoring).

## Error

Something failed and the event did not do what it was meant to do. These are what the default alert rules watch.

| Code | What it means |
|---|---|
| `ATTACHMENT_NOT_FOUND` | The file no longer exists — it was removed between the event and the delivery |
| `ATTRIBUTE_TYPE_MISMATCH` | An attribute value did not match the type declared in the entity schema |
| `CONDITIONAL_VARIANT_WRITE_FAILED` | Conditional pricing refused one variant write. The item is dropped and not retried; the rest of the batch and the run continue. details.code names the reason where pricing gave one — UNKNOWN_ERROR means it did not |
| `CORRELATION_ID_MISSING` | A request asked for something that only makes sense for a correlation, but did not say which correlation |
| `CORRELATION_REQUIREMENT_FAILED` | Something a caller was waiting for can no longer arrive: every event that would have satisfied the requirement ended in an error. Reported once per correlation |
| `DEPRECATED_ENDPOINT` | This endpoint version is deprecated |
| `DIRECT_ENTITY_NOT_ALLOWED` | The entity is not permitted by the use case entity allowlist |
| `DIRECT_PAYLOAD_INVALID` | The direct mode payload failed validation against the versioned payload schema |
| `DIRECT_VERSION_UNSUPPORTED` | The direct mode payload version is not supported by the platform |
| `ENTITY_REFERENCE_NOT_FOUND` | A direct-by-id entity reference points at an entity that does not exist or has a different schema |
| `EVENT_NOT_CONFIGURED` | No mapping configuration found for this event type |
| `EXTERNAL_API_ERROR` | An external API returned an error |
| `EXTERNAL_ERROR` | An error span pushed by an external system (e.g. your integration middleware) via the external monitoring events endpoint. epilot assigns the code from the span's level; the middleware never sends one. |
| `FAN_OUT_INVALID_RESULT` | The split expression returned something other than a list, so no deliveries could be created — see split_expression_result_type |
| `FILE_EXTRACTION_FAILED` | Failed to extract file from the request |
| `FILE_FETCH_FAILED` | The file could not be fetched from epilot before it could be uploaded |
| `FILE_PROXY_UPLOAD_FAILED` | A file upload failed terminally, or every delivery attempt was exhausted |
| `FILE_TOO_LARGE` | The file exceeds the maximum size configured on the upload use case |
| `INTEGRATION_NOT_FOUND` | The inbound event referenced an integration_id that does not exist in the calling token's organization. Check the integration id and that the token belongs to the same org. |
| `INVALID_METER_READING_ATTRIBUTES` | Meter reading has invalid attributes |
| `MALFORMED_PAYLOAD` | The event payload could not be parsed (malformed JSON) |
| `MAPPING_EXPRESSION_FAILED` | A mapping expression failed to evaluate |
| `METERING_API_ERROR` | The metering API returned an error |
| `METER_READING_GROUP_FAILED` | A batch write of meter readings failed permanently after all retries — summary event alongside the per-reading errors |
| `METER_READING_GROUP_RETRYING` | A batch write of meter readings failed and will be retried automatically — one event per attempt covering the whole group (reading_count and external_ids in details) |
| `MISSING_REQUIRED_PARAM` | A required parameter is missing from the request |
| `MISSING_UNIQUE_IDENTIFIERS` | The event is missing the unique identifier field(s) required to match an entity |
| `MSG_DEAD_LETTERED` | Outbound message moved to the dead-letter queue after exhausting delivery attempts, or via an operator skip |
| `MSG_EXPIRED_UNPOLLED` | Outbound message expired before being consumed — retention elapsed without a successful poll |
| `MSG_HEAD_BLOCKED` | Outbound stream halted by a poison head message (block policy) — requires operator unblock or consumer acknowledgement |
| `OAUTH2_TOKEN_FAILURE` | Failed to obtain an OAuth2 access token |
| `PAYLOAD_TOO_LARGE` | The payload exceeded the maximum size accepted by the receiving system |
| `PROCESSING_STATE_LIMIT` | The processing record of an interactive event could not be written, because it or its correlation reached the size the store allows, so the event was ended as an error instead of being left processing: its correlation still completes, and anyone waiting on it is answered. The event's data may have been written all the same. Usually a payload with unusually many entities or very long unique ids |
| `PRUNE_SCOPE_PARTIAL_FAILURE` | Scope pruning completed with some failures |
| `RECURSION_DEPTH_EXCEEDED` | Maximum recursion depth was exceeded during processing |
| `RELATION_REF_ITEM_NOT_FOUND` | The relation_ref value could not be matched on the target entity (invalid mapped value, or still no match after writing it to the target) — skipped as non-retryable. Check the mapping configuration and the entity data. |
| `RELATION_REF_VALUE_UNDEFINED` | A relation_ref mapping value resolved to undefined — check the mapping expression |
| `REQUIRED_PARAM_MISSING` | A param the use case marks as required resolved to nothing, so the delivery was stopped before anything was sent — see param_name |
| `SECURE_PROXY_DISABLED` | The secure proxy use case is disabled |
| `SECURE_PROXY_DOMAIN_BLOCKED` | The target domain is blocked |
| `SECURE_PROXY_DOMAIN_NOT_ALLOWED` | The target domain is not in the allowlist |
| `SECURE_PROXY_ERROR` | An error occurred in the secure proxy |
| `SECURE_PROXY_INVALID_CONFIG` | The secure proxy configuration is invalid |
| `SECURE_PROXY_INVALID_TYPE` | The secure proxy type is invalid |
| `SECURE_PROXY_INVALID_URL` | The target URL is invalid |
| `SECURE_PROXY_IP_BLOCKED` | The target IP address is blocked |
| `SECURE_PROXY_IP_NOT_ALLOWED` | The target IP address is not in the allowlist |
| `SECURE_PROXY_NOT_FOUND` | The secure proxy use case was not found |
| `SECURE_PROXY_UNAVAILABLE` | Secure proxy service is unavailable |
| `SIGNATURE_VERIFICATION_FAILED` | Request signature could not be verified |
| `SIGNATURE_VERIFICATION_UNAVAILABLE` | The file service could not be reached to verify the request signature |
| `STEP_DISABLED` | A request step's "run this step when" expression returned false, so this step and every step after it were skipped. This is the configuration working as written, not a fault. |
| `TIMEOUT` | The operation timed out |
| `UNIQUE_ID_LOOKUP_UNRESOLVABLE` | A related entity created for this event still could not be found by its unique ID, so the relation was skipped instead of creating a duplicate. Check that the unique ID value type matches the entity schema. |
| `UNIQUE_ID_MULTIPLE_MATCHES` | Multiple entities matched the unique ID |
| `UNIQUE_ID_NOT_IN_SCHEMA` | The unique ID attribute is not defined in the entity schema |
| `UNKNOWN_ERROR` | An unexpected error occurred during processing |
| `USE_CASE_DISABLED` | The use case is currently disabled |
| `USE_CASE_INVALID_TYPE` | The use case type is invalid or unsupported |
| `USE_CASE_MISSING_CONFIG` | The use case is missing required configuration |
| `USE_CASE_NOT_FOUND` | The use case could not be found |

## Warning

Processing continued, but something needs a human eye — often a retry in flight or a value nobody has mapped yet.

| Code | What it means |
|---|---|
| `ACK_TIMEOUT` | Acknowledgement timed out waiting for the ERP system |
| `CONDITIONAL_VARIANT_WRITE_WARNING` | One variant write succeeded with a warning. The variant is stored and the rest of the batch and the run continue. details.code names the warning |
| `CORRELATION_CLOSED_INCOMPLETE` | The partner declared a correlation complete and everything it sent was processed, but what the caller was waiting for was not in it — see `missing_entities` and `missing_use_cases`. Reported once per correlation |
| `CORRELATION_CLOSE_IGNORED` | The partner declared a correlation complete, but the close was not applied: the same request has to be retried, the queue refused one of its events, the correlation does not exist and the request recorded nothing under it (its events carried their own correlation ids, were duplicates, matched no use case, or were not processed as interactive), a close without events found the organization over its interactive rate and could not create the correlation, or the correlation belongs to another integration (the one whose event or close created it). The reason names the cause. Retry with `correlation_complete`, send the close under the correlation the events were recorded under, or use a correlation id of your own |
| `CORRELATION_EVENT_LIMIT_EXCEEDED` | This correlation already holds as many events as one correlation may, so further events sent under it were processed normally and cannot be waited on. A correlation is meant to cover one registration or one change; this usually means the partner sends the same correlation id with every push. Each request that should be waited on needs its own id |
| `CORRELATION_LATE_EVENT` | An event arrived under a correlation the partner had already declared complete. It was processed, but anyone waiting on that correlation had already been answered, and once the correlation is complete the event cannot change that answer — the partner is sending `correlation_complete` too early |
| `CORRELATION_WAIT_REJECTED` | A caller tried to wait on a correlation while too many waits were already open, so it was asked to retry. Its data is unaffected — only the answer it was waiting for is slower |
| `CORRELATION_WAIT_TIMEOUT` | A caller waited on a correlation until its time ran out without getting what it asked for — see `missing_entities` and `missing_use_cases` for what had not arrived. Reported once per correlation. When nothing at all was sent under the correlation, it carries no integration: none is known before the first event |
| `EXTERNAL_WARNING` | A warning span pushed by an external system via the external monitoring events endpoint. |
| `FILE_PROXY_UPLOAD_RETRYING` | A file upload failed with a retryable error and will be retried automatically — one event per attempt |
| `INTERACTIVE_CROSS_LANE_WRITE` | The same entity was updated from two different processing lanes within seconds of each other, one of them the interactive lane. Both updates were applied; this reports that they overlapped, so the order they landed in was decided by timing |
| `INTERACTIVE_RATE_LIMITED` | The organization asked for interactive processing more often than its agreed rate, so these events were processed on its normal lane instead. Nothing was lost and the correlation can still be waited on — it will simply take as long as a bulk event does |
| `LOOKUP_UNMAPPED` | A value was not listed in a lookup table and its fallback was used — see lookup_name and lookup_key for the gap |
| `MSG_LATE_ARRIVAL` | An event arrived after the poll consumer had already received later events, so it was placed at the end of the stream instead of at its event time — it is delivered, but out of event-time order |
| `SOFT_DELETED_ENTITY_MATCHED` | A soft-deleted entity matched the unique ID — it will be resurrected on upsert, or referenced as-is by a relation. Investigate why the ERP source is sending events for a deleted entity. |

## Success

The event did what it was meant to do. Useful for confirming a sync actually landed.

| Code | What it means |
|---|---|
| `ACK_CONFIRMED` | Acknowledgement was confirmed by the ERP system |
| `CONDITIONAL_VARIANTS_WRITTEN` | Conditional price variants were written for one imported entity: emitted once per chunk, with a per-outcome count and the variant ids in details |
| `ENTITY_CREATED` | A new entity was created in epilot |
| `ENTITY_DELETED` | An entity was deleted from epilot |
| `ENTITY_NO_OP` | No changes were needed for the entity |
| `ENTITY_UPDATED` | An existing entity was updated in epilot |
| `EXTERNAL_SUCCESS` | A success span pushed by an external system via the external monitoring events endpoint. |
| `FILE_PROXY_OK` | File proxy request completed successfully |
| `FILE_PROXY_UPLOADED` | The external system accepted the file |
| `METER_READING_DELETED` | One or more meter readings were deleted — emitted once per batch, not per reading (reading_count and external_ids in details) |
| `METER_READING_UPSERTED` | One or more meter readings were created or updated — emitted once per batch, not per reading (reading_count and external_ids in details) |
| `MSG_ACKED` | Outbound message delivered: the polling consumer acknowledged it and it was removed from the queue |
| `PRUNE_SCOPE_COMPLETED` | Scope pruning completed successfully |
| `WEBHOOK_DELIVERED` | Webhook was delivered successfully |

## Info

Lifecycle markers rather than outcomes: a message was queued, a duplicate was ignored, a step was skipped by configuration. Counted in total events, but excluded from the success rate.

| Code | What it means |
|---|---|
| `ACK_PENDING` | Acknowledgement is pending from the ERP system |
| `CORRELATION_CLOSED_EMPTY` | The partner declared a correlation complete without sending any event for it. That is the partner reporting "I found nothing", and anyone waiting is told so at once instead of waiting it out |
| `CORRELATION_COMPLETED` | Every event the partner sent under this correlation has finished processing and the partner declared the correlation complete |
| `DUPLICATE_EVENT` | This event was already processed (duplicate) |
| `EXTERNAL_INFO` | An informational span pushed by an external system via the external monitoring events endpoint. |
| `FAN_OUT_EMPTY` | The split expression returned an empty list, so nothing was sent — expected for events that carry no relevant items |
| `FILE_PROXY_UPLOAD_ENQUEUED` | A per-file upload was accepted for delivery during fan-out |
| `INTERACTIVE_NOT_ALLOWED` | Interactive processing was requested for a use case that is not configured for it, so the events were processed normally. Set `interactive` to `on_request` or `always` on the use case if the caller is meant to be able to wait for these events |
| `MSG_ENQUEUED` | Outbound message enqueued to the poll queue, awaiting consumption by the ERP. When the use case maps the payload, the detail carries the mapped payload as delivered and its mapping_version (or payload_omitted when it exceeds 48 KiB) |
## Status-code families

Some codes are generated from an upstream response rather than drawn from the fixed list above.

| Pattern | Level | What it means |
|---|---|---|
| `HTTP_{status}` | warning | The upstream system answered the proxied request with this HTTP status. The proxy itself worked — it reached the target and returned its answer — so the refusal is recorded against the use case that owns the request. |