Skip to content

Error codes

The coded errors that server functions throw, and the error codes the public API returns. For the functions themselves, see Server functions and routes.

codedError(code, message) in server/lib/errors.ts throws an Error whose message is CODE: message. Other failures, including the authz helpers’ refusals, throw a plain Error with no code.

The client reads the prefix with /^([A-Z_]+):\s*(.*)$/ and shows its own text for the codes it knows, or the message after the prefix (components/map-editor/lib/collections.ts, hooks/use-field-mutations.ts).

Where the code is: grep -rn codedError apps/app/src/server.

Code Thrown when
LABEL_TOO_LONG A node label passed to createNode or updateNode is longer than 255 characters.
NODE_NOT_IN_MAP A node named in a write isn’t in the map.
NODE_NOT_PLACED moveNodes names a node that has no position.
MAX_NODES_EXCEEDED placeNodes would take the map past 200 placed nodes, or moveNodes gets more than 200 moves.
DELETE_FAILED network.delete_node_from_map fails in deleteNode.
NODE_SELF_CONNECTION A connection’s source and target are the same node.
CONNECTION_INVALID_NODES A connection’s source or target isn’t in the map.
CONNECTION_DATE_INVALID A connection date isn’t a year, month or day, or a period ends before it starts.
PROPERTY_KEY_REQUIRED promoteNodeProperty gets a blank key.
PROPERTY_KEY_NOT_FOUND No node in the map has the property promoteNodeProperty names.
PROPERTY_NOT_NUMERIC The property promoteNodeProperty names has a non-numeric value.
Code Thrown when
FIELD_NOT_FOUND A measure, tag, connection type or field id isn’t in the map’s catalogue.
FIELD_NOT_IN_MAP A value write breaks the value-to-definition FK, so the definition is in another map.
FIELD_VALUE_TYPE_MISMATCH A value’s JavaScript type doesn’t match its measure or connection type.
FIELD_VALUE_NOT_TRUE A boolean connection type is given false.
FIELD_IS_A_TAG setNodeField names a tag instead of a measure.
TAG_GROUP_CONFLICT A node would carry two tags from one tag group.
TAG_GROUP_CLASH Moving a tag into a group would give some nodes two of its tags. The message names them.
Code Thrown when
FIELD_NAME_REQUIRED A field is created or renamed with a blank name.
FIELD_DIRECTIONALITY_NOT_APPLICABLE A measure or tag is given a directionality or inverse name.
FIELD_INVERSE_NAME_NOT_APPLICABLE A connection type that isn’t directed is given an inverse name.
FIELD_VALUE_META_NOT_APPLICABLE A value label or unit is given to anything but a numeric connection type.
FIELD_CONVERSION_UNSUPPORTED updateField is asked to turn a tag into a measure.
TAG_STYLE_NOT_APPLICABLE A measure or connection type is given an icon or colour.
TAG_ICON_INVALID A tag’s icon isn’t one of TAG_ICONS or 'none'.
TAG_COLOUR_INVALID A tag’s colour isn’t one of TAG_COLOURS.
TAG_GROUP_NAME_TAKEN A tag group is created or renamed to another group’s name.
TAG_GROUP_NOT_FOUND A tag group id isn’t in the map.
Code Thrown when
IMPORT_FILE_ROLES_INVALID createImportSession gets no files, the wrong number of files, or file roles that don’t make one elements file.
IMPORT_SCAN_FAILED An uploaded file can’t be read from Storage or parsed.
IMPORT_SESSION_NOT_FOUND The import session doesn’t exist or the caller can’t see it.
IMPORT_SESSION_INVALID The import session has no target map.
IMPORT_SESSION_NOT_READY ingestImportSession is called on a session not in previewing or mapping.
IMPORT_MAPPING_INVALID A CSV mapping breaks a column rule, such as two label columns or a role the scan ruled out.
IMPORT_MAPPING_NAME_CONFLICT A CSV mapping would create a field with a blank name, or two fields with one name.
IMPORT_MAPPING_INCOMPLETE Ingest starts with no label or id column, or before a required mapping step is confirmed.
Code Thrown when
RECIPE_TOO_LONG saveRecipe gets a body over 20,000 characters.
RECIPE_NOT_FOUND confirmRecipe is called on a map with no recipe, or a blank one.
Code Thrown when
VIEW_NOT_FOUND updateSavedView (server/lib/saved-views.ts) names a view the map doesn’t have.
Code Thrown when
NOT_IMPLEMENTED A scaffolded function with no body is called (functions/not-implemented.ts).

Every v1 error has the shape { "error": { "code", "message", "details"? } }. details is a list of { path, message }, present only for invalid_document.

Code Status Returned when
invalid_request 400 The request is malformed: bad params, bad JSON, an empty, multipart or compressed body.
invalid_document 400 An imported document or a changes body fails validation; nothing is written.
unauthorized 401 The API key is missing or invalid.
forbidden 403 The key’s member has lost access to the org, or the map is in another org.
not_found 404 The map, field or view doesn’t exist, or there’s no recipe to validate.
method_not_allowed 405 The route doesn’t support the method; the Allow header lists the ones it does.
conflict 409 A same-named connection type exists with a different value type or directionality, a tag group conflict, or two views share the name a POST …/views gives.
payload_too_large 413 The body exceeds its limit (1 MB for JSON, 10 MB for import and changes).
internal_error 500 Anything else; the real error is logged, not returned.

Where the code is: apps/app/src/server/api/v1/errors.ts. The OpenAPI document (GET /api/v1/openapi.json) describes the shape as its Error schema.

The v1 handlers call the same editing code as the app, so they can receive coded errors. withApiErrors passes each thrown error to apiErrorFromCoded, which maps these codes to an API error:

Coded error Status API code
FIELD_NAME_REQUIRED 400 invalid_request
FIELD_DIRECTIONALITY_NOT_APPLICABLE 400 invalid_request
FIELD_INVERSE_NAME_NOT_APPLICABLE 400 invalid_request
FIELD_VALUE_META_NOT_APPLICABLE 400 invalid_request
FIELD_CONVERSION_UNSUPPORTED 400 invalid_request
FIELD_NOT_IN_MAP 400 invalid_request
FIELD_NOT_FOUND 404 not_found
TAG_GROUP_CONFLICT 409 conflict
TAG_GROUP_CLASH 409 conflict
TAG_STYLE_NOT_APPLICABLE 400 invalid_request
TAG_ICON_INVALID 400 invalid_request
TAG_COLOUR_INVALID 400 invalid_request
RECIPE_TOO_LONG 400 invalid_request
RECIPE_NOT_FOUND 404 not_found
VIEW_NOT_FOUND 404 not_found

The message after the prefix becomes the API message. Any other coded error becomes a 500 internal_error. To report a new code as the caller’s mistake, add it to CODED_ERROR_STATUS.