API Error Code Catalog

View as Markdown

This catalog covers stable codes reachable through API-key-authenticated /api/v1 routes. It excludes internal X Bookmarks codes and codes emitted only by dashboard sessions, OAuth, billing, or other non-API-key routes.

Codes can appear at the top level, inside warnings[], inside validation.errors[], or per URL in mediaResults[]. Match on the code, not the human-readable message.

For retry patterns and idempotency guidance, see Error Handling.

Request and scheduling codes

Code HTTP Location Meaning Retryable? Recovery
IDEMPOTENCY_IN_FLIGHT 409 top-level code Another request with this idempotency key is still running, or its claim was superseded Yes, shortly Retry the identical request with the same key
IDEMPOTENCY_KEY_CONFLICT 422 top-level code The key was already used with a different body or resource No, unchanged Replay the original request or use a new key for the new operation
IDEMPOTENCY_BODY_TOO_COMPLEX 400 top-level code The body is too deeply nested to hash safely for idempotency No Simplify the request body or omit Idempotency-Key if safe retries are not required
PLATFORM_SETTING_UNKNOWN 400 top-level code A platformSettings path is outside the strict allowlist No Remove or correct the path named by field
PLATFORMS_REQUIRED 400 top-level code Scheduling would leave the post with no target platforms No Add at least one platform, or keep the post as a draft
SCHEDULED_TIME_IN_PAST 400 top-level code Strict mode rejected a time at least five minutes in the past No Send a future ISO 8601 UTC time
SCHEDULED_TIME_COERCED 200 warnings[].code A past time was clamped to server time during the warn-first ramp Not an error Read the returned scheduledTime and fix the caller to send a future time
MEDIA_VALIDATION_PENDING 200 warnings[].code Scheduling succeeded while bounded media probing remained transiently incomplete Not an error Monitor the post; media is checked again before publishing
MEDIA_NOT_READY 400 top-level code Attached upload bytes are missing, still uploading, or previously failed validation After fixing media Complete/re-upload the media, then schedule again
MEDIA_URL_RATE_LIMITED 429 top-level code The fixed-window allowance of 60 ingested URLs was exceeded Yes Wait the Retry-After seconds, then retry; preserve the idempotency key when applicable

Plan and workspace limit codes

These top-level codes are LimitExceededError responses with HTTP 403.

Code Meaning Retryable? Recovery
CONNECTIONS_OVER_LIMIT The workspace already has more connected channels than its plan permits After account changes Disconnect channels or upgrade before scheduling
CHANNEL_LIMIT_REACHED Adding or attaching would exceed the channel allowance After account changes Disconnect a channel or upgrade
SCHEDULE_HORIZON_REACHED The requested time is farther ahead than the plan permits No, unchanged Choose an earlier time or upgrade
SCHEDULED_POST_LIMIT_REACHED The active scheduled-post queue is full After capacity frees Wait for or delete an existing scheduled post, or upgrade
POST_LIMIT_REACHED The monthly account/connection post allowance is exhausted After reset or upgrade Wait for periodEnd or upgrade
PLATFORM_NOT_AVAILABLE The plan does not allow one or more selected platforms No, unchanged Remove the platforms listed in the top-level disallowedPlatforms array or upgrade

Media completion codes

These codes are returned by POST /complete-media/{mediaFileId}.

Code HTTP Location Meaning Retryable? Recovery
INVALID_MEDIA_FILE_ID 400 top-level code mediaFileId is not a Mongo ObjectId No Use the mediaId returned by get-upload-url
MEDIA_FILE_NOT_FOUND 404 top-level code No media row belongs to the caller for that ID No Check the ID and API-key owner; upload again if it was deleted
MEDIA_FILE_INDETERMINATE_TYPE 400 top-level code Neither stored type nor MIME prefix identifies image, video, or PDF No Re-upload with the correct Content-Type
PROBE_FAILED 400 top-level code The stored media already failed byte-level validation No Re-upload a valid file
MEDIA_FILE_MISSING_URL 500 top-level code The media row has no storage URL No client-side retry contract Upload again; contact support if newly created rows repeat this state
PROBE_VERSION_UNVERIFIED 503 top-level code The object version could not be verified before or after probing Yes Retry complete-media after a few seconds
PROBE_DOWNLOAD_FAILED 503 top-level code A transient S3/CDN download prevented probing Yes Retry complete-media after a few seconds
PROBE_VERSION_CHANGED 503 top-level code The uploaded object changed while it was being validated Yes, after upload stabilizes Stop overwriting the presigned object and retry
MEDIA_FILE_RACE 409 top-level code The row was deleted or failed concurrently during probing No Re-upload and use the new media ID

mediaUrls per-URL codes

When create/update ingestion fails, the request returns HTTP 400 with error: "Media ingestion failed"; the URL/fetch codes below can appear in mediaResults[].code. Probe failures are forwarded into the same field using the applicable code from Media completion codes. The batch is all-or-nothing.

Code HTTP Location Meaning Retryable? Recovery
MEDIA_URL_INVALID 400 mediaResults[].code The value is not a URL No Supply a valid public URL
MEDIA_URL_PROTOCOL 400 mediaResults[].code The URL is not HTTPS No Use https://
MEDIA_URL_CREDENTIALS 400 mediaResults[].code The URL embeds a username or password No Use a credential-free URL, such as a signed HTTPS URL
MEDIA_URL_PORT 400 mediaResults[].code The URL uses a non-default HTTPS port No Serve it on port 443
MEDIA_URL_BLOCKED_HOST 400 mediaResults[].code The host or resolved address is private/blocked No Use a publicly reachable host
MEDIA_URL_DNS 400 mediaResults[].code DNS returned no usable address After DNS is fixed Correct DNS, then retry the whole request
MEDIA_URL_REDIRECT 400 mediaResults[].code A redirect lacked a Location header After the origin is fixed Use the final URL or fix the redirect
MEDIA_URL_TOO_MANY_REDIRECTS 400 mediaResults[].code The fetch exceeded the redirect limit No, unchanged Use a direct URL
MEDIA_URL_HTTP_ERROR 400 mediaResults[].code The remote server returned a non-200 response After the origin is available Check access/expiry and retry with a working URL
MEDIA_URL_INGEST_TIMEOUT 400 mediaResults[].code The request-wide media ingestion budget expired Conditionally Use a faster origin, smaller media, or the presigned upload flow
MEDIA_URL_TOO_LARGE 400 mediaResults[].code One image/video exceeds the URL-ingestion byte cap No Use a smaller file or get-upload-url
MEDIA_URL_AGGREGATE_TOO_LARGE 400 mediaResults[].code Combined downloaded bytes exceed 300 MiB No Reduce the batch or use presigned uploads
MEDIA_URL_UNSUPPORTED_FORMAT 400 mediaResults[].code Magic-byte detection found an unsupported format No Convert to a supported image/video format
MEDIA_URL_FETCH_FAILED 400 mediaResults[].code An unexpected network/download failure occurred Conditionally Verify the URL and retry once; otherwise use presigned upload
MEDIA_URL_PROBE_FAILED 400 mediaResults[].code Defensive fallback if a future failed probe supplies no specific code; current probeAndPersistMedia failure branches always supply one Not currently expected If observed, convert or re-upload valid media and report the unexpected fallback
MEDIA_URL_SKIPPED 400 mediaResults[].code This URL was not attempted after another URL failed After fixing the root failure Correct the failing URL and retry the complete batch
MEDIA_URL_ROLLED_BACK 400 mediaResults[].code This URL succeeded, but its media was removed because another URL failed After fixing the root failure Correct the failing URL and retry the complete batch

LinkedIn symbolic errors

These LinkedIn endpoints use the error field for stable symbolic values rather than a separate code field.

Value HTTP Meaning Retryable? Recovery
REACTION_ALREADY_EXISTS 409 The actor already has a reaction on the target post No, unchanged Delete the existing reaction, then apply the requested type
LINKEDIN_TOKEN_EXPIRED 401 The stored LinkedIn access token is expired No Reconnect the LinkedIn account
LINKEDIN_RATE_LIMITED 429 LinkedIn is rate-limiting the analytics resource/account Yes Wait the returned retryAfter seconds
LINKEDIN_REQUEST_TIMEOUT 504 The backend request deadline elapsed while waiting for LinkedIn Yes Retry the read/interaction with normal backoff

Post validation codes

Scheduling validation returns HTTP 400. These codes appear in validation.errors[].code; validation warnings, when present, use validation.warnings[].code.

Code Meaning Recovery
CONTENT_TOO_LONG Content exceeds the selected platform's character limit Shorten it or change the target platform/account tier
CONTENT_OR_MEDIA_REQUIRED The post has neither usable text nor media Add content or media
MEDIA_REQUIRED A selected platform requires media Attach supported images or video
MEDIA_SIZE_EXCEEDED A file exceeds the platform byte limit Compress or replace it
MEDIA_COUNT_EXCEEDED Too many media items are attached Delete extras and schedule again
MEDIA_TYPE_NOT_SUPPORTED The media type is unsupported for the platform Convert or remove it
MEDIA_DIMENSIONS_INVALID Image/video dimensions violate a platform rule Resize the media
MEDIA_ASPECT_RATIO_INVALID Aspect ratio violates a platform rule Crop or resize the media
VIDEO_REQUIRED The selected platform requires video Attach a supported video
VIDEO_DURATION_EXCEEDED Video is longer than the platform maximum Trim it
VIDEO_DURATION_TOO_SHORT Video is shorter than the platform minimum Use a longer video
IMAGES_NOT_SUPPORTED The selected platform does not accept images for this post type Remove images or change the target
DOCUMENTS_NOT_SUPPORTED The selected platform does not accept document media Remove the document or target LinkedIn
PLATFORM_SETTING_REQUIRED A required platform-specific setting is absent Supply the field identified in the error
PLATFORM_SETTING_INVALID A platform-specific setting has an invalid value Use one of the reported accepted values
PLATFORM_NOT_SUPPORTED The validator has no contract for the target platform Remove the unsupported target

All validation codes above are non-retryable with the unchanged request.

Workspace attachment codes

These lowercase codes are top-level response fields from POST /workspace/users or POST /workspace/users/attach.

Code HTTP Meaning Recovery
email_exists 409 A user with the requested email already exists Inspect the returned attachment status; use the attach flow when allowed
missing_identifier 400 Neither email nor user ID was supplied Send one identifier
invalid_user_id 400 The user ID is malformed Send a Mongo ObjectId
invalid_email 400 The email format is invalid Correct the email
user_not_found 404 No active target user was found Check the identifier
identifier_mismatch 400 Supplied email and user ID identify different users Correct one identifier
user_inactive 409 The target user is inactive Reactivate the user before attaching
cannot_attach_self 400 The workspace owner was supplied as the target Choose another user
user_is_workspace_owner 409 The target owns a workspace A workspace owner cannot be attached as managed
user_in_another_workspace 409 The target already belongs to another workspace Detach it from the other workspace first
user_has_active_subscription 409 The target has a blocking subscription Resolve that subscription before attaching
attach_consent_required 403 Attaching an existing standalone user requires its consent token Supply the target user's access token
invalid_attach_consent 403 The consent token is invalid or revoked Obtain a fresh token from the target user
attach_consent_mismatch 403 The token belongs to another user Supply the target user's own token

Source coverage

  • Top-level scheduling and idempotency responses: backend/src/app/routes/apiRoute.js.
  • Plan/workspace entitlement responses: backend/src/app/services/limitsService.js.
  • Scheduling guards and media state: backend/src/app/helpers/scheduledPlatformsGuard.js, mediaStatusTransitions.js, and probeMediaUpload.js.
  • Per-URL ingestion: backend/src/app/helpers/mediaUrlIngest.js and mediaUrlSecurity.js.
  • Validation codes actually emitted by scheduling: backend/src/app/services/postValidationService.js and errors/ValidationError.js.
  • Workspace attachment responses: backend/src/app/controllers/workspaceApiController.js.
  • LinkedIn interaction/analytics errors: backend/src/app/controllers/linkedinController.js.