Skip to content

Errors

Every error response uses the same shape. The HTTP status code tells you the broad category; the error.code tells you the precise reason.

Error format

json
{
  "error": {
    "code": "validation_failed",
    "message": "The request body did not match the expected schema.",
    "request_id": "req_8f3a1c2d4e5b6a7f",
    "details": {
      "field": "variants[0].price",
      "reason": "must be a number"
    }
  }
}
FieldTypeAlways presentPurpose
codestringYesMachine-readable error identifier. Use this for branching in your client. The full list lives in Humind error codes.
messagestringYesHuman-readable summary. Short, English-only. Don't display raw to end users, it's written for developers.
request_idstringYesUnique identifier for this request. Attach it to support tickets so we can find the matching server logs.
detailsobjectNoPer-error context: which field failed validation, which scopes were missing, which field caused an idempotency conflict, etc. The shape depends on code.

HTTP status codes

CodeMeaningWhen it's returned
200 OKSuccessGET, PUT, PATCH, POST upserts that updated an existing resource.
201 CreatedResource createdPOST that created a new resource.
204 No ContentSuccess, no bodyDELETE.
207 Multi-StatusPer-item statuses in batchPOST /products/batch. Top-level is 207; each item in the response carries its own status code. See Batch upsert.
400 Bad RequestMalformed or invalid requestBody isn't valid JSON (invalid_json), schema validation fails (validation_failed), or a required header is missing/too long (idempotency_key_required, idempotency_key_too_long).
401 UnauthorizedAuth failureMissing, malformed, invalid, revoked, or expired API key.
403 ForbiddenAuth succeeded but disallowedKey is valid but lacks the required scope for this endpoint.
404 Not FoundResource doesn't exist or belongs to another tenantIncludes "exists but belongs to another company", we never leak cross-tenant existence.
409 ConflictIdempotency reuse with different bodyThe Idempotency-Key was used before with a different request body.
413 Payload Too LargeBody over 5 MBTrim the payload or split into batches. Returns payload_too_large.
415 Unsupported Media TypeWrong/missing Content-TypeA write request (POST, PUT, PATCH) didn't send Content-Type: application/json. Returns unsupported_media_type.
422 Unprocessable EntityResource-level invariant violatedCurrently used for cannot_delete_last_variant, wrong_type, file_not_uploaded, invalid_lang_format, tag_resolution_failed, and the import / webhook state-machine errors. Plain "field X is wrong" validation issues return 400 validation_failed.
429 Too Many RequestsThrottledPer-API-key rate limit (rate_limited) or auth-layer IP throttle (too_many_failures).
500 Internal Server ErrorUnexpected error on our sideIncludes the request_id. Safe to retry with the same Idempotency-Key.
502 / 503 / 504Upstream / capacity issueTransient. Retry with backoff using the same Idempotency-Key.

Humind error codes

CodeHTTPMeaningHow to fix
missing_credentials401No Authorization header, or it doesn't start with Bearer .Add Authorization: Bearer hmd_live_... to the request.
invalid_key_format401The token doesn't match hmd_(live|test)_<22>_<8>.Check for trailing whitespace, missing characters, or pasted ellipsis. See Key format.
invalid_checksum401The 8-char checksum at the end of the token doesn't match the rest. Almost always a copy-paste typo.Re-copy the key from the dashboard, or regenerate it if you can no longer access the original.
invalid_key401Token has the right shape but doesn't match any active key (unknown, revoked, or expired).Verify the key in your dashboard. If it was revoked, create a new one.
revoked401The key was revoked manually or via "regenerate".Create a new key and update your secret store.
expired401The key has an expires_at in the past.Create a new key; consider not setting an expiry or set it further out.
insufficient_scope403The key is valid but doesn't have a scope this endpoint requires. details.required lists the required scopes; details.missing lists the ones missing.Create a new key with the missing scopes. Scopes are immutable, you can't add scopes to an existing key. See Scopes.
validation_failed400The body parsed but the body didn't match the resource schema; details.issues lists each offending field with its path, message, and code.Fix the field(s) and resend. The same Idempotency-Key is safe to reuse on the corrected request only if the body change is the validation fix; in practice, generate a new UUID.
invalid_json400The request body isn't valid JSON.Verify your serialization. The Content-Type: application/json header is required and the body must parse with JSON.parse.
payload_too_large413Request body exceeds the 5 MB limit.Split into smaller payloads. For catalog backfills use POST /products/batch (up to 500 items per call) or the Imports async pipeline.
unsupported_media_type415The request omitted Content-Type: application/json on a POST, PUT, or PATCH (or sent a different content-type).Set Content-Type: application/json on every write request.
not_found404The resource doesn't exist, or belongs to a different company.Check the id you passed. If you're using api:<external_id>, confirm the external_id exists for this company.
idempotency_conflict409An Idempotency-Key was reused with a different request body.Generate a fresh UUID for this request. Reuse the key only when retrying the exact same request.
idempotency_key_required400A state-changing call (POST, PUT, PATCH, DELETE) was made without an Idempotency-Key header on an endpoint that now requires it.Add an Idempotency-Key: <uuid> header. See Idempotency.
idempotency_key_too_long400The Idempotency-Key header exceeds 255 characters.Use a UUID v4 (36 chars) or any short unique value.
idempotency_in_progress409The same Idempotency-Key is currently being processed by another concurrent request.Wait for the original request to finish, then retry with the same key, the cached response will be replayed.
duplicate_external_id_in_batch-The same external_id appeared more than once in a batch payload (POST /products/batch, POST /collections/batch, POST /knowledge/batch). The first occurrence is processed normally; later duplicates are returned with status: "failed" in the per-item result. Surfaced inside the 207 body, not as a top-level HTTP error.Deduplicate external_ids in your batch payload before sending.
handle_already_used409A POST / PUT / PATCH on /collections set a handle that already belongs to a different collection in this company (matched on a different external_id). details.handle carries the offending value.Pick a different handle, or PATCH the existing collection (matched by external_id) instead of creating a new one.
tag_resolution_failed422A tag name in tags couldn't be resolved or created (rare). details.tag carries the offending name.Retry with the same body. If it persists, share the request_id with support.
translation_not_found404A translation sub-resource GET targets a {lang} that has no translation stored on the resource. DELETE is idempotent and does not raise this code.Confirm the locale code, or use the parent resource's translations field to see which locales exist.
variant_not_found404The {variant_external_id} on a variant sub-resource call doesn't match any variant on the product. DELETE is idempotent and does not raise this code.Confirm the variant's external_id against the parent product's variants array.
invalid_lang_format422The {lang} segment of a translation sub-resource URL doesn't match ^[a-z]{2}(-[A-Z]{2})?$.Use a BCP 47 short tag like en, fr, de, pt-BR.
webpage_fetch_failed-A webpage knowledge entry's URL fetch failed. Surfaced via the entry's status='failed', not a top-level HTTP error.Verify the URL is publicly reachable and HTML, then PATCH the entry to re-queue. See The webpage type.
wrong_type400A type-specific knowledge endpoint (e.g. /file-upload-url, /file-upload-completed) was called on an entry whose discriminator doesn't match. The error message echoes the actual type.Either retarget the call to a matching entry, or use the right endpoint for the entry's type. See The file type.
file_not_uploaded422POST /knowledge/{id}/file-upload-completed was called before the merchant PUT the file payload to the SAS URL minted by /file-upload-url.Complete the upload PUT first, then retry. See The file type.
too_many_failures429An IP has accumulated too many failed auth attempts in a short window.Stop probing. Verify your key, then retry after one minute.
import_not_pending422start or cancel was called on an import that's not in the right state for that transition (e.g. start on an already processing / done / failed / cancelled import).Check status first via GET /imports/{sync_id}. Each lifecycle transition is one-way.
import_blob_missing422start was called on an import for which no NDJSON file has been uploaded yet (the blob behind upload_url returns 404).PUT the file to upload_url first, then call start. See Imports.
webhook_endpoint_not_found404The webhook endpoint :id doesn't match an endpoint owned by your company.Confirm the id. Cross-tenant lookups also return 404. See Webhooks.
invalid_event_type422An entry in events on POST / PATCH /webhooks/endpoints isn't a known event type.Use one of the values listed in Available events.
invalid_url422The url on a webhook endpoint isn't a valid HTTPS URL, or points to a private host (localhost, 127.0.0.1, RFC1918) in live mode.Use a publicly reachable https:// URL. For local dev, use a hmd_test_* key with a tunnel.
webhook_disabled422An attempt to interact with a disabled webhook endpoint in a way that requires it to be active.Re-activate via PATCH /webhooks/endpoints/:id with { "status": "active" }.
internal_error500Unexpected server-side failure.Retry with backoff. If it persists, contact support with the request_id.

Debugging tips

  • Always log the request_id alongside the status code and error.code in your client. Including it in a support ticket cuts our triage time from "find a needle in 500k log lines" to "look up one record".
  • Don't loop on 401s. A 401 means human-in-the-loop intervention is needed (verify the key, rotate it, fix the header). Re-retrying a bad key just trips the too_many_failures cooldown.
  • Treat 5xx as transient. Retry with exponential backoff and the same Idempotency-Key. We log every 5xx with the request_id; if you see a pattern, share the IDs with support.
  • 400 vs 422. A 400 covers anything wrong with the request envelope or the schema: invalid JSON, missing/oversized headers, a field with the wrong type or out of range. A 422 is reserved for resource-level invariants the schema alone can't express — e.g. "you can't remove the last variant of a product", or "this knowledge entry's type doesn't match the endpoint you called". Most validation errors are 400; if you see 422, look at the specific code in the table above.

Next

  • Authentication: full list of auth-related codes (missing_credentials, invalid_checksum, revoked, …) in context.
  • Conventions: request format and idempotency, the source of most validation errors.
  • Products: per-endpoint error tables.

Released under the proprietary Humind license.