vercel/ai · error

OpenCode session create returned no id.

Error message

OpenCode session create returned no id.

What it means

After a successful session-create call, ensureSession reads the session id out of the response with readSessionId. If the id cannot be found, the bridge throws this error. It means the OpenCode server responded OK but with a body that does not carry a recognizable id field — almost always an API contract/version mismatch.

Source

Thrown at packages/harness-opencode/src/bridge/index.ts:595

  if (start.resumeSessionId) {
    const existing = await legacySessionGet({
      client,
      sessionId: start.resumeSessionId,
    }).catch(() => undefined);
    if (existing && !existing.error) {
      runtime.sessionId = start.resumeSessionId;
      emit({ type: 'bridge-thread', threadId: runtime.sessionId });
      return runtime.sessionId;
    }
  }
  const created = await legacySessionCreate({ client });
  if (created.error) {
    throw new Error(
      `OpenCode session create failed: ${formatError(created.error)}`,
    );
  }
  const id = readSessionId(created.data);
  if (!id) throw new Error('OpenCode session create returned no id.');
  runtime.sessionId = id;
  emit({ type: 'bridge-thread', threadId: id });
  return id;
}

async function runPrompt({
  client,
  sessionId,
  start,
  turn,
  emit,
}: {
  client: OpenCodeClient;
  sessionId: string;
  start: StartMessage;
  turn: BridgeTurn;
  emit: Emit;
}): Promise<HarnessUsage | undefined> {

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Check the actual session-create response shape from your OpenCode server (curl the endpoint) and compare with what readSessionId expects.
  2. Align the OpenCode server version with the harness-bridge version that matches the response format.
  3. If behind a proxy, ensure it does not strip or transform the JSON body.
  4. Log created.data (e.g. patch or wrap the client) to see what the server actually returned.

Example fix

// before: server returns { data: { session: { id } } } but bridge reads data.id
const id = readSessionId(created.data); // undefined -> throws
// after: upgrade @ai-sdk/harness-opencode / OpenCode server to matching versions
pnpm update @ai-sdk/harness-opencode opencode
Defensive patterns

Strategy: type-guard

Validate before calling

const probe = await fetch(`${base}/session`, { method: 'POST', body: '{}' }).then(r => r.json());
if (!probe || (typeof probe.id !== 'string' && typeof probe.data?.id !== 'string')) {
  throw new Error('OpenCode session-create response missing id — check server version');
}

Type guard

function hasSessionId(data: unknown): data is { id: string } {
  return typeof data === 'object' && data !== null && 'id' in data && typeof (data as { id: unknown }).id === 'string';
}

Try / catch

try {
  await agent.run(...);
} catch (e) {
  if (e instanceof Error && e.message === 'OpenCode session create returned no id.') {
    console.error('Response shape mismatch — dump server response and align versions');
  } else throw e;
}

Prevention

When it happens

Trigger: legacySessionCreate resolves without created.error but readSessionId(created.data) returns undefined, e.g. the server returns a wrapped/envelope response, a snake_case id field, or an empty body the bridge's reader does not understand.

Common situations: OpenCode server upgraded/changed its session-create response shape; a proxy strips or rewrites the response body; running against a mock/incompatible server implementation.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/7c96fb729cd4cbfb. Report an issue: GitHub.