Nodaro Docs
DocumentationNode ReferenceModelsAI Agents (MCP)DevelopersSelf-hostingResearch
REST API

Errors

Every Nodaro API error has an HTTP status and a stable code in one envelope. Learn what each code means, which errors to retry, and how failed jobs report why.

Every Nodaro API error returns an HTTP status and one JSON envelope with a stable code, so your client can dispatch on the code instead of parsing messages. There are two kinds of failure: a request error, when the call itself is refused and nothing starts, and a job failure, when a generation that started fails later and reports why on the job.

The error envelope

{ "error": { "code": "rate_limited", "message": "Too many requests. Max 30 per minute." } }
  • code is a stable slug. Dispatch on it.
  • message is text for people. It can change, so never match on it.
  • Some errors add fields, listed with each code below. Most sit inside error; already_running puts executionId beside error, and a failed pre-run allowance check puts required and remaining at the top level.

The OAuth token endpoint is the one exception: it answers in the OAuth format, for example { "error": "invalid_grant", "error_description": "…" }. See OAuth apps.

Which errors to retry

StatusWhat to do
5xxUsually temporary. Retry with exponential backoff.
429Wait, then retry with backoff: for example 5, then 10, then 20 seconds. Honor a Retry-After header when there is one.
402Add credits, or ask a workspace admin for budget, then retry.
Other 4xxFix the request first. The same request fails again.

Three server errors need care:

  • 503 price_not_configured does not succeed on retry: the model has no price on this deployment until its operator sets one.
  • 503 provider_unavailable on the asynchronous structured LLM route is permanent on an install that sends its language-model calls to nodaro.ai.
  • When publishing to social networks, 503 publish_retryable means nothing was posted and the same request is safe to send again, but 500 publish_failed means the outcome is unknown, and sending again can post twice.

Error codes

400 Bad Request

CodeMeaning
validation_errorA malformed body, a bad UUID, an invalid field or a malformed cursor.
limit_reachedYou already have 10 API tokens, active or not. Delete one first.
invalid_workflowA token's workflowIds entry is not a workflow in your personal space.
token_workspace_mismatchA token bound to one workspace was sent with an X-Nodaro-Workspace header naming another.
locked_fieldA run tried to change where an outbound node sends or fetches. See What a run cannot change.
image_requiredPOST /v1/generate-video without a start frame, on a model that cannot make video from text. The message says whether references would work instead.
sequence_execution_requiredThe run includes Studio production nodes that must be generated through the Studio production API.
not_workspace_scopedYou changed visibility on a workflow that is not in a workspace.
advanced_mode_unsupportedadvancedMode: true on a model that has no direct lane.

401 Unauthorized

CodeMeaning
unauthorizedThe token is missing, invalid, expired or revoked.

402 Payment Required

These codes come from Nodaro Cloud and from deployments that bill.

CodeExtra fieldsMeaning
insufficient_creditsrequired, balanceThe account is out of credits. On a deployment with one billing account, it means the deployment's pool is empty: the error then carries required but never balance, and only the billing account can add credits.
insufficient_app_creditsA published app's run: the account is out of credits.
budget_exceededWork paid by a workspace: the workspace budget cannot cover the run. Ask a workspace admin for more.
member_cap_exceededWork paid by a workspace: your own spending cap in that workspace is reached.
user_allowance_exceededrequired, remainingA deployment with one billing account that enforces per-user allowances: your allowance cannot cover the run. Only the billing account can raise it.
instance_cap_reachedAn OAuth token of a connected self-hosted install: the install has spent its monthly cap on the account that connected it. Raise or remove the cap under Connected Instances.

403 Forbidden

CodeExtra fieldsMeaning
forbiddenThe token's workflow scope does not include this workflow, or the route needs a signed-in session. See Authentication.
insufficient_scopemissingScopeAn OAuth token lacks a scope the route needs. Send the user through consent again with the wider scope.
in_app_onlyThe route exists only for the Nodaro web app, such as the Workflow Copilot.
edition_requiredrequired_editionThe route needs a higher edition: cloud for pipeline branching, business for API token management.
not_a_memberThe X-Nodaro-Workspace header names a workspace you are not an active member of.
member_suspendedYour membership in the workspace is suspended.
personal_space_disabledYour organization lets you create work only inside a workspace. Send the workspace header.
project_create_not_allowedOnly the workspace's admins may create projects.
workspace_archivedA write into an archived workspace, such as sharing a workflow. Creating work there answers 409 instead.
not_permittedThe workflow is not yours to move, or not yours to move there.
sso_requiredThe deployment restricts sign-in to its identity provider, and this session's account was not created through it. Tokens are not affected.
subscription_requiredA pay-as-you-go account spent from the web editor. Pay-as-you-go credits work through the API, the SDK, the CLI and MCP, so token calls never get this code.
api_tokens_payer_onlyOn a deployment with one billing account, only that account can create API tokens.
payer_balance_jwt_onlyOn such a deployment, the billing account read the pool's balance with a token. Only its own browser session may.
payer_requiredA deployment billing route was called by anything but the billing account's browser session.

404 Not Found

CodeMeaning
not_foundThe resource does not exist, or you cannot see it. The two are deliberately the same answer, so an id never reveals whether something exists.
workspace_not_foundWork paid by a workspace names a workspace that does not exist.

409 Conflict

CodeExtra fieldsMeaning
already_runningexecutionIdThe workflow already has an active run. Poll that run instead.
workflow_conflictcurrentVersion, currentUpdatedAt, currentRecordThe workflow changed since the version you sent. Merge onto currentRecord and save again.
workspace_archivedYou tried to create or move work into an archived workspace.
workspace_has_no_default_projectA create in a workspace named no project, and the workspace has none. Name a project.
move_blockedThe work was created for an assignment and cannot be moved.
production_capability_requiredA generic workflow save touched a Studio production that needs its own API.
retained_image_in_useA delete would remove protected images, or a production still has jobs using them. Finish or cancel those jobs first.

413, 422 and 429

StatusCodeMeaning
413Your account is over its storage limit. The SDK raises StorageExceededError with limitBytes.
422job_blockedThe deployment's job policy refused the generation before it ran. No job was created and nothing was charged. Show message to your user as it is, and do not retry the same request.
422upload_blockedThe deployment's upload policy refused a file before it was stored. Show message as it is.
429rate_limitedThe per-token limit of a personal API token.
429rate_limit_exceededAny other limit: per address, per route, or a published app's daily runs.
429too_many_downloadsYou already have 4 video imports running.

The 422 codes happen only on deployments that register such a policy. See Rate limits for the 429 codes.

500 and 503

StatusCodeMeaning
500internal_errorA server error or a failure of a service it depends on. Retry with backoff.
503price_not_configuredThe requested model has no price on this deployment, so the server refuses instead of billing wrongly. Retrying does not help.
503rate_limit_unavailableA spending route could not check its rate limit. Retry later.
503provider_unavailableThe model's provider is not available.
503billing_unavailableUsage reporting is not available on this instance yet.

When a job fails later

A request that succeeded can still produce a job that fails. The job then carries error_message, and for two kinds of failure a structured error_hint:

  • { "kind": "safety-block", "class": "copyright" | "likeness" | "safety", "retried": boolean, "suggestedProvider"?: string } when a model's safety filter blocked the request.
  • { "kind": "policy-block", "policyId": string, "reason": string, "hookPoint": "request" | "result" } when a deployment's policy rejected it.

Both are always refunded, and credit_status on the job shows it. Read Why a job failed for what each field means and when to try another model.

Errors in the SDK

@nodaro/sdk throws a typed error for every failed response. Catch the most specific class first:

ClassStatusExtra fields
UnauthorizedError401
ForbiddenError403missingScope when the code is insufficient_scope
NotFoundError404
InsufficientCreditsError402required, available
StorageExceededError413limitBytes
WorkflowConflictError409currentVersion, currentUpdatedAt, currentRecord. Also used for the Studio production_busy conflict.
RateLimitedError429
JobBlockedError422
StudioOpError4xxopIndex: which operation of a Studio batch was refused
NodaroErroranyThe base class: code, status and message
import {
  NodaroError,
  ForbiddenError,
  InsufficientCreditsError,
  RateLimitedError,
} from '@nodaro/sdk'

try {
  await client.workflows.run(workflowId)
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    showPaywall({ required: err.required, available: err.available })
  } else if (err instanceof ForbiddenError && err.missingScope) {
    requestConsent([err.missingScope])
  } else if (err instanceof RateLimitedError) {
    await new Promise((r) => setTimeout(r, 5_000))
  } else if (err instanceof NodaroError) {
    console.error(`API error ${err.status} (${err.code}): ${err.message}`)
  } else {
    throw err // a network failure, not an API error
  }
}

The polling helpers add their own errors, such as JobFailedError and JobTimeoutError. See Run a single node.

Errors in the CLI

Exit codeMeaning
0Success.
1Unauthorized, not found, a wrong argument or a network error.
2--watch ended and the run failed.
3--watch stopped because the job is held for review. It is not a failure: check back later.
130--watch ended and the run was cancelled.

With --json, the CLI prints the payload and exits normally instead of using codes 2, 3 and 130, so check .status yourself.

Frequently asked questions

Last updated on

On this page