Skip to main content
Reference

Errors and error codes

Look up a Result error code, an SDK exception class, or a qodercli exit code, and decide how to handle it.

This page is the reference for error identity: given a code, an exception class, or an exit code, what it means and how to handle it. If you have a symptom rather than a code — a hang at startup, a tool the agent ignores, a setting that appears to have no effect — start from Troubleshooting, which is indexed by observed behavior. Qoder Agent SDK reports task failures, SDK failures, and process exits separately. Handle the most specific signal available instead of treating every non-success condition as an exception.
What failed?
   |
   +-- Agent completed the task unsuccessfully
   |      `result` message: subtype, errors, optional error_code
   |
   +-- SDK could not start or maintain the session
   |      thrown exception: class, code, and diagnostic fields
   |
   `-- qodercli process stopped
          process exit code: transport-level diagnostic
The error_code in a Result message and the qodercli process exit code are different namespaces. Do not compare one with values from the other.
  1. Consume messages until the SDK produces a result or raises an exception.
  2. For a Result, check subtype and is_error first. Use error_code only to choose a more specific recovery path when it is present.
  3. Catch SDK exceptions around the entire iteration. Use the exception type and fields to diagnose configuration, runtime, or transport failures.
  4. Log the session ID, Result subtype, error code, and exception name. Do not log authentication values or full source content by default.
An unsuccessful Result and a later process exception can describe the same failed session. Record both for diagnostics, but avoid showing the user two notifications for one failure.

Result subtypes

subtypeMeaningRecommended action
successThe Agent completed the turnRead result and continue or close the session
error_during_executionThe turn stopped because of an execution, model, service, authentication, or unrecoverable tool errorRead errors; use error_code when available; retry only when the cause is transient
error_max_turnsThe Agent reached its configured turn limitInspect for loops or blocked tools, then increase the limit only if more turns are appropriate
Future runtimes can add Result subtypes. Always keep a fallback branch that records the subtype and errors instead of assuming this table is exhaustive.

Handle Results

TypeScript exposes an optional number | string error_code on SDKResultMessage; Python exposes an optional numeric code on ResultMessage. TypeScript preserves CLI string codes such as storage_insufficient and unknown codes unchanged. Use the field when it is present, and do not extract a code by parsing human-readable error text. Java's ResultMessage has no error code field. outcome() returns the normalized result SUCCESS, ERROR, or UNKNOWN, and wireSubtype(), wireIsError(), and errors() correspond to subtype, is_error, and errors. Read error_code from rawJson() when you need it.
import {
  QoderCliProcessError,
  accessTokenFromEnv,
  query,
} from '@qoder-ai/qoder-agent-sdk';

let resultReceived = false;

try {
  for await (const message of query({
    prompt: 'Run the test suite and explain any failures.',
    options: { auth: accessTokenFromEnv() },
  })) {
    if (message.type !== 'result') continue;

    resultReceived = true;
    if (message.subtype === 'success' && !message.is_error) {
      console.log(message.result);
      continue;
    }

    console.error({
      subtype: message.subtype,
      errorCode: message.error_code,
      errors: 'errors' in message ? message.errors : [message.result],
      sessionId: message.session_id,
    });

    if (message.error_code === 105) {
      // Obtain a new credential and create a new SDK session.
    } else if (
      typeof message.error_code === 'number' &&
      [500, 10408, 10500].includes(message.error_code)
    ) {
      // Retry later with bounded exponential backoff.
    }
  }
} catch (error) {
  if (error instanceof QoderCliProcessError) {
    console.error({
      exitCode: error.exitCode,
      signal: error.signal,
      stderr: error.stderr,
      resultReceived,
    });
  } else {
    throw error;
  }
}

Result error codes

The following numeric codes are normalized by the current qodercli runtime and can appear in message.error_code in the TypeScript and Python SDKs; Java reads the error_code field from ResultMessage.rawJson(). The field is optional. qodercli can also pass through a numeric service code not listed here, so preserve unknown values in logs and fall back to subtype plus errors.

Authentication and quota

CodeMeaningRecommended action
105Login or access token expiredObtain a valid credential and create a new session; register the authentication-expired callback
110Daily usage limit reachedWait for the usage window to reset or review the account limit
113Usage quota exhaustedReview quota and plan status; do not immediately retry unchanged
114Free-trial account limit reachedReview account eligibility or upgrade options
115Free-user quota reachedWait for quota renewal or review upgrade options
116Team administrator Credits exhaustedAsk the team administrator to replenish or adjust Credits
117Team member Credits exhaustedAsk the team administrator to assign or replenish Credits
118Personal Credits exhaustedReplenish Credits or use an account with available capacity
119Free usage limit for the selected model reachedSelect an available model, wait for renewal, or review the plan
122Billing-group Credits limit reachedAsk the billing administrator to review the group limit

Request and policy

CodeMeaningRecommended action
406Request blocked because of sensitive content or model refusalChange the request or input content; do not retry it unchanged
416Requested range or request shape is not satisfiableInspect errors, then reduce or correct the requested range
430Requested capability is not supportedUpgrade to compatible SDK/qodercli versions or use a supported capability
47902Maximum Agent turns reachedInspect loops, permissions, and tool failures before increasing the turn limit
48716A Hook blocked Agent executionInspect the relevant Hook decision and update the Hook or task
80411Input content is too longReduce the prompt, attachments, or retained context
80412Too many images or documentsReduce the number of media attachments and retry

Service and model runtime

CodeMeaningRecommended action
500Request or network failureCheck connectivity and retry with bounded exponential backoff
10408Request timed outRetry with bounded backoff; reduce task scope if timeouts repeat
10500Model service internal errorRetry later; retain the session ID when contacting support
10605Model request is queuedqodercli normally waits and retries; if the code reaches the Result, retry later
Retry only errors known to be transient. Use a maximum attempt count, exponential backoff, and jitter. Authentication, quota, policy, input, and configuration errors require a change before retrying.

SDK exceptions

SDK exceptions mean the application could not configure, start, control, or continue the session. They are separate from an unsuccessful Agent Result.
SituationTypeScriptPythonJavaUseful fields
Authentication not configuredError with code: "auth_not_configured"Error with code: "auth_not_configured"InvalidOptionsExceptioncode; Java getCode()
PAT environment variable missingAuthAccessTokenEnvVarErrorAuthAccessTokenEnvVarErrorAuthenticationExceptioncode; Java getCode()
Service Account environment variable missingAuthServiceAccountEnvVarErrorAuthServiceAccountEnvVarError—code
qodercli not found or cannot startQoderCliProcessErrorCLINotFoundError / CLIConnectionErrorCliNotFoundException, RuntimeInstallException, or QoderException with error code CLI_START_FAILEDmessage; TypeScript stderr; Python path/message; Java getCode()
qodercli exits unexpectedlyQoderCliProcessErrorProcessErrorCliProcessException; AuthenticationException for exit code 41exitCode / exit_code, stderr; TypeScript signal; Java getExitCode(), getStderrTail()
Model selection callback times outModelPolicyTimeoutErrorModelPolicyTimeoutErrorNo exception; see the note after the tabletimeoutMs / timeout_ms
Protocol version is incompatibleProtocolVersionMismatchErrorProtocolVersionMismatchErrorProtocolVersionMismatchExceptionCLI and SDK protocol versions
Runtime lacks a required capabilityUnsupportedCliCapabilityErrorUnsupportedCliCapabilityErrorUnsupportedCliCapabilityExceptioncapability; Java capabilityState()
CLI returns a failure before initialization completesQoderCliInitializationError——message, code, result
A Java model selection callback timeout is not delivered to the application as an exception, so catch cannot see it. The SDK answers the CLI with error code MODEL_RESOLUTION_TIMEOUT and sends an inbound_control_request_failed event to the diagnostics listener, with error=MODEL_RESOLUTION_TIMEOUT in detail. To detect this case, register a DiagnosticsListener and handle the turn's result through ResultMessage.outcome(), reading errors() when it is ERROR. In TypeScript, startup() and query.initializationResult() throw QoderCliInitializationError when the CLI returns a failure Result before initialization completes. Its message preserves the CLI error text, code preserves the optional numeric or string error_code, and result contains the original Result. Cancellation remains AbortError. Failures after initialization continue to arrive as Result messages. Machine-readable authentication configuration codes shared by the TypeScript and Python SDKs are:
codeMeaning
auth_not_configuredNo authentication method was provided
auth_access_token_env_var_not_configuredThe configured PAT environment variable is absent
auth_service_account_env_var_not_configuredThe configured Service Account environment variable is absent
For expired credentials reported after startup, use onAuthExpired / on_auth_expired and create a new session with a valid credential. Java has no such callback; handle AuthenticationException instead. See SDK Authentication.

Exceptions and error codes (Java)

Custom Java SDK exceptions all extend the unchecked QoderException; get the stable error code with getCode(). Argument and configuration errors are thrown synchronously at the call site; for example, a failed build() validation throws InvalidOptionsException. Startup and runtime failures are delivered through the message cursor's hasNext() / next(), the stage returned by consume(), or the stage returned by other asynchronous methods. When you wait with join(), they are wrapped in CompletionException; use getCause() to get the original exception. The SDK never retries automatically, and isRetryable() returns false for every built-in exception. How to handle common error codes:
Error codeHow to handle
INVALID_OPTIONSFix the configuration; retrying does not help
AUTHENTICATION_FAILED, CLI_AUTH_FATALFix the credential or account permissions, then create a new query or session
CLI_NOT_FOUND, RUNTIME_INSTALL_FAILED, CLI_START_FAILED, UNSUPPORTED_SECURE_SECRET_TRANSPORTCheck the CLI path, the managed CLI download, and the startup environment; see Troubleshooting
CLI_PROCESS_FAILEDRecord getExitCode() and getStderrTail()
UNSUPPORTED_CLI_CAPABILITYThe current CLI does not support the feature you called. If you specified the CLI yourself, switch to the SDK-managed pinned version; otherwise do not use the feature
SESSION_CLOSEDThe resource is closed; stop calling it and create a new session if needed
MESSAGE_STREAM_ALREADY_CONSUMEDEach message stream can be consumed only once; openCursor() and consume() together can be called only once
SPOOL_CAPACITY_EXCEEDEDUnconsumed messages exceeded the buffer limit. Read the message stream promptly
The following error codes mean the session has terminated: QUERY_WRITE_FAILED (the one-shot query input was not written to the CLI), CONTROL_WRITE_FAILED (a control request or response was not written to the CLI), TURN_ACCOUNTING_FAILED (turn state can no longer be processed), and MESSAGE_DELIVERY_FAILED (a buffered message could not be decoded). The original session cannot be used again: close the handle and log the cause with getCause(). To continue the conversation, create a new session with the original session ID through SessionOptions.Builder.resume(String). When a thread blocked in MessageCursor.hasNext() or next() is interrupted, it throws ConsumerInterruptedException, and the thread's interrupt flag stays set. To stop reading, close the cursor:
Java
try {
    while (cursor.hasNext()) {
        handle(cursor.next());
    }
} catch (ConsumerInterruptedException e) {
    // The interrupt flag is still set; stop reading and release the session.
    cursor.close();
}
Closing the cursor closes its query or session asynchronously. For the full list of exceptions and error codes, see Java exception list.

qodercli process exit codes

Applications using the SDK should normally handle Results and SDK exceptions instead of branching directly on process exit codes. Exit codes are most useful for transport diagnostics or when qodercli is started outside the SDK.
Exit codeMeaning
0Process exited normally
1General or unclassified failure
41Authentication failure; the SDK also triggers the authentication-expired callback when configured. Java reports it as AuthenticationException with error code CLI_AUTH_FATAL
42Invalid input or command-line arguments
44Fatal sandbox error
52Fatal configuration error
53Fatal turn-limit error
54Fatal tool-execution error
130Cancellation or interrupt
Other exit codes or termination signals can come from the operating system, a custom runtime, or a child process. TypeScript exposes them through QoderCliProcessError.exitCode and .signal; Python exposes an available code through ProcessError.exit_code; Java exposes it through CliProcessException.getExitCode().

Logging and support

For an actionable failure record, retain:
  • SDK language and version
  • qodercli version from the system/init message, when available
  • session_id, Result subtype, optional error_code, and errors
  • Exception class, machine-readable code, process exit code, and signal
  • Whether the failure happened before initialization, during a tool call, or after a Result
Redact PATs, Service Account keys, authorization headers, full prompts, source files, and tool output unless they are explicitly required for an approved diagnostic workflow.

Next steps