{
"code": "BAD_REQUEST",
"message": "Invalid input: expected string, received undefined",
"requestId": "37a04f8f-e791-491c-81e1-86cd304649bb",
"docs": "https://docs.nomos.energy/api-references/errors/BAD_REQUEST"
}
| Field | Description |
|---|---|
code | Machine-readable error code. Switch on this in your handler. |
message | Human-readable description of what went wrong. |
requestId | Unique request identifier. Include it when contacting support. |
docs | Link to the reference page for this code. |
errors | Optional. Per-field breakdown of a validation or business-rule failure (see Structured errors). |
Always log the
requestId alongside the request that caused the error. It’s
the fastest way for support to find the corresponding trace.Structured errors
When a request fails validation or a business rule, the envelope carries an additionalerrors array with a per-field breakdown. Switch on each entry’s code to map the failure back to a specific input, instead of parsing the human-readable message.
The
errors array is available from version 2026-05-27.curie onwards. On
earlier versions the envelope omits it and only code, message,
requestId, and docs are returned.{
"code": "BAD_REQUEST",
"message": "We don't currently serve this postal code.",
"requestId": "37a04f8f-e791-491c-81e1-86cd304649bb",
"docs": "https://docs.nomos.energy/api-references/errors/BAD_REQUEST",
"errors": [
{
"code": "unserviceable_zip",
"field": "address.zip",
"message": "We don't currently serve this postal code."
}
]
}
| Field | Description |
|---|---|
code | Machine-readable reason for this field. Either a standard validation code (invalid_type, too_small, …) or a Nomos-specific business code (unserviceable_zip). |
field | Dot-path to the offending field (address.zip). Empty for a top-level issue. |
message | Human-readable description of this specific issue. |
code stays the coarse HTTP class (for example BAD_REQUEST); the errors[].code values are the granular reasons you switch on.
Validation codes
These cover schema validation failures and map to the underlying validator’s issue codes.| Code | Description |
|---|---|
invalid_type | Wrong type for the field, or the field is missing entirely. |
too_big | Value exceeds its maximum (number too large, string or array too long). |
too_small | Value is below its minimum (number too small, string or array too short). |
invalid_format | String doesn’t match the expected format (email, UUID, ISO date, …). |
not_multiple_of | Number isn’t a multiple of the required step. |
unrecognized_keys | The object contains keys that aren’t allowed, or a filter the endpoint rejects. |
invalid_union | Not surfaced directly in errors[]; unions are flattened into their branch issues. |
invalid_key | A key in a record or map is invalid. |
invalid_element | An element of a set or map is invalid. |
invalid_value | Value isn’t one of the allowed options (enum or literal mismatch). |
custom | A custom validation rule failed with no more specific code. |
Business error codes
Beyond the validation codes above,errors[].code can carry a Nomos-specific business code:
Business error codes are available from version
2026-05-27.curie onwards. On
earlier versions these failures surface only through the top-level code and
message.| Code | Status | Description |
|---|---|---|
unserviceable_zip | 400 | The postal code in address.zip is outside the area Nomos serves. |
unsupported_product | 400 | A requested entry in product_orders isn’t offered by the subscription’s plan. |
duplicate_customer_email | 400 | A customer with this email already exists under a different type, name, or company. Reconcile before retrying. |
invalid_iban | 400 | The IBAN in payment_method.sepa_debit.iban failed checksum validation. |
unsupported_meter | 400 | The plan doesn’t support the capacity (RLM) meter named in meter.type. |
unsupported_meter_order | 400 | The subscription’s plan offers no smart meter product, so a meter order can’t be placed. |
duplicate_meter_order | 409 | An active meter order of this product already exists for the subscription. |
ended_subscription | 400 | The subscription has ended, so a grid fee reduction can’t be created for it. |
duplicate_grid_reduction | 400 | An active §14a EnWG grid fee reduction already exists for this module on the subscription. |
missing_smart_meter | 400 | §14a EnWG module 3 requires a smart meter, which the subscription doesn’t have. |
missing_module_1 | 400 | §14a EnWG module 3 can only be ordered together with module 1. |
out_of_period_meter_reading | 400 | The reading timestamp is outside the subscription period or in the future. |
unsupported_meter_reading | 400 | Meter readings can only be reported for analog meters; this subscription’s meter is smart. |
duplicate_meter_reading | 409 | A meter reading already exists for this day. Resubmitting the identical value returns the stored reading instead. |
implausible_meter_reading | 422 | The reading implies a daily consumption that is implausibly high or low compared to previous readings. |
upgrade_api_version | 400 | The request targets a feature (such as feed-in subscriptions) not available on the requested API version. Upgrade to a newer version. |
invalid_termination_date | 409 | The requested intended_end_at is in the past, or earlier than the plan’s cancellation period or the grid operator’s notice period allow. |
withdrawal_not_allowed | 409 | The 14-day withdrawal window has passed, or the subscription has no confirmation date to count it from. |
subscription_not_started | 400 | The subscription never started supply (e.g. it was withdrawn before the switch completed), so no prices are available for it. |
missing_household | 400 | Several of the customer’s households match the meter, so Nomos cannot pick one. Pass the household explicitly. |
invalid_household_customer | 400 | The household in household belongs to a different customer than the one in this request. |
invalid_household_meter | 400 | The meter is not registered at the household in household. Pass the household the meter belongs to, or leave it empty to create one. |
duplicate_consumption_subscription | 400 | The household in household already has a live consumption subscription on another meter. A separately metered device needs its own household. |
invalid_inverter | 400 | parent_inverter is not an active inverter in the same household, is set on a type other than solar or battery, or is missing on a solar asset. |
read_only_asset | 400 | Nomos maintains household_net and household_residual: they can’t be added or decommissioned, and an update only changes their metadata. |
duplicate_external_id | 409 | An asset of your organization already has this external_id, active or decommissioned. The message names its ID. |
asset_has_children | 409 | The inverter still has active solar or battery assets behind it. Decommission them or move them to another inverter first. |
asset_decommissioned | 409 | The asset is decommissioned: it can’t be updated or decommissioned again, and takes no snapshots measured after its decommissioning. |
asset_not_found | 404 | An asset in the request does not exist or belongs to another organization. |
mixed_households | 400 | One request may only carry the assets of one household. Send each household in its own request. |
field_not_allowed | 400 | The field does not apply here, for example a charge level on a solar asset or any value on an offline snapshot. |
invalid_direction | 400 | The power flows in a direction the asset cannot have, for example solar consuming. Power is positive into the asset and negative out of it. |
duplicate_timestamp | 400 | Two snapshots of one asset in the request have the same timestamp but different values. Send one value per asset and moment. |
Retrying
Retry only when retrying could plausibly succeed. Use exponential backoff with jitter and cap the attempts.| Status | Retry |
|---|---|
4xx | No. Fix the request before retrying. |
5xx | Yes, with exponential backoff. |
Error reference
| Status | Code | Description |
|---|---|---|
400 | BAD_REQUEST | The request is invalid: a field fails validation, a business rule rejects it, or the body isn’t valid JSON. errors[] names each field and its reason. |
401 | UNAUTHORIZED | No credentials, or the access token is invalid or expired. Refresh and retry. See Authentication. |
403 | FORBIDDEN | Valid token, but it may not use this endpoint: its scope lacks read:* or write:*, or its role has no access. |
404 | NOT_FOUND | A resource in the path or the body doesn’t exist, or belongs to another organization. Double-check the ID. |
409 | CONFLICT | The request conflicts with the current state of a resource: a duplicate such as an existing meter order, or a resource in the wrong state such as an already terminated subscription. |
422 | UNPROCESSABLE_ENTITY | A query parameter is invalid, such as a filter value outside its allowed options or a date that doesn’t exist, or a meter reading is implausible. Read errors[] for the details. |
500 | INTERNAL_SERVER_ERROR | Unexpected error on Nomos’s side. Retry with backoff. If it persists, email support@nomos.energy with the requestId. |