decolua/9router · error

Trae create_session: ${JSON.stringify(json)}

Error message

Trae create_session: ${JSON.stringify(json)}

What it means

After a successful HTTP create-session POST, Trae wraps its real status in the JSON body with a code field where 0 means success. createSession() throws this error when the response parses as JSON but code !== 0, serializing the whole body so the developer can see Trae's error code and message.

Source

Thrown at open-sse/executors/trae.js:130

        model_name: modelName,
        agent_type: "solo_agent_remote",
        model_selection_strategy: strategy,
        common_params: this.commonParams(psd, mode),
      },
      env: "remote",
      auto_create_project: false,
      origin: "web",
    };
    const res = await proxyAwareFetch(`${this.base()}/chat_sessions`, {
      method: "POST",
      headers,
      body: JSON.stringify(body),
      signal,
    }, null);
    const text = await res.text();
    if (!res.ok) throw new Error(`[${res.status}] ${text}`);
    const json = JSON.parse(text);
    if (json?.code !== 0) throw new Error(`Trae create_session: ${JSON.stringify(json)}`);
    return { sessionId: json.data.chat_session_id, messageId: json.data.message_id };
  }

  // GET /events SSE → invoke onEvent(eventType, dataObj) per frame.
  // Resolves when `done`/`error` arrives, the stream ends, or timeout fires.
  async streamEvents(headers, sessionId, replyTo, onEvent, signal) {
    const url = `${this.base()}/chat_sessions/${sessionId}/events?reply_to_message_id=${encodeURIComponent(replyTo)}`;
    const ctrl = new AbortController();
    if (signal?.aborted) ctrl.abort();
    const timer = setTimeout(() => ctrl.abort(new Error("trae stream timeout")), STREAM_TIMEOUT_MS);
    const onAbort = () => ctrl.abort();
    if (signal) signal.addEventListener("abort", onAbort, { once: true });
    try {
      const res = await proxyAwareFetch(url, { method: "GET", headers, signal: ctrl.signal }, null);
      if (!res.ok || !res.body) throw new Error(`[${res.status}] events stream failed`);
      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buf = "";

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Inspect the JSON in the message — the msg field names the app-level cause; map the code to quota vs auth and act accordingly
  2. Re-authenticate or refresh the Trae credential if the code indicates auth rejection
  3. Wait for quota reset or switch accounts if the code indicates rate/quota limits (enable account fallback)
  4. Retry; transient app errors can clear on a new session
  5. Update 9router if Trae added new error codes requiring handling
Defensive patterns

Strategy: try-catch

Type guard

function isTraeSuccess(json) {
  return json != null && typeof json === 'object' && json.code === 0 && json.data != null;
}

Try / catch

try {
  session = await executor.createSession(...);
} catch (e) {
  if (String(e.message).includes('Trae create_session:')) {
    const body = e.message.slice(e.message.indexOf('{'));
    const { code, msg } = JSON.parse(body);
    log.warn('trae app error', { code, msg });
    return failoverAccount(req);
  }
  throw e;
}

Prevention

When it happens

Trigger: The create-session endpoint returns 200 with an application-level error body: {code: <nonzero>, msg: ...} — quota exhausted, auth rejected at the application layer, session limit reached, or feature disabled for the account.

Common situations: Trae free-tier daily quota consumed; application-level token invalid despite HTTP 200; account restrictions/region enforcement; Trae API version drift introducing new nonzero codes.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/2f63924f8719e778. Report an issue: GitHub.