Errors and statuses

Handle HTTP failures and terminal run outcomes consistently.

HTTP success means Epho accepted or read the request. A run can still settle as failed, timed out, or canceled, so asynchronous clients must inspect the turn status.

HTTP status codes

StatusMeaning
200Successful read or synchronous SSE stream
201Signup or device OAuth ticket created
202Turn queued or cancellation accepted
401Missing or invalid Epho bearer token
402Team has no positive compute credit
403Invalid device OAuth polling secret
404Resource not found, outside the token's team, or unsupported OAuth provider
409Another turn is already running in this chat
422Request validation failed
429Signup or OAuth polling rate limit exceeded

Validation errors

Laravel validation responses use an errors object:

{
  "message": "The given data was invalid.",
  "errors": {
    "model": [
      "Unsupported model for the selected harness."
    ]
  }
}

Common causes include:

  • missing prompt, harness, or model;
  • an unsupported harness/model pair;
  • a missing provider key for a paid model;
  • an unsupported CPU or memory value;
  • invalid environment-variable names or limits;
  • malformed input files;
  • duplicate or reserved MCP server names;
  • sending env or mcp_servers while resuming a chat.

Turn statuses

StatusTerminalMeaning
processingnoQueued, provisioning, resuming, or running
completedyesAgent finished successfully
failedyesLaunch or agent execution failed
timed_outyesAgent timed out or stopped heartbeating
canceledyesClient requested cancellation

Read the error field when a terminal status is not completed.

{
  "turn_id": "01K...",
  "status": "failed",
  "output": null,
  "error": "Failed to start the run.",
  "artifacts": []
}

Retry guidance

  • Retry 429 only after respecting the response's rate-limit timing.
  • Do not retry 422 without changing the request.
  • For 409, wait for the active turn or use a different chat.
  • A submission that returned 202 should be tracked through its existing turn_id; do not create a duplicate turn just because polling is quiet.
  • Lifecycle events and SSE keepalives distinguish queued or quiet work from a disconnected client.