{"record":{"id":"f73eff68e15e72a1","repo":"different-ai/openwork","slug":"serializesdkerror-result-error","errorCode":null,"errorMessage":"serializeSDKError(result.error)","messagePattern":"serializeSDKError\\(result\\.error\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/react-app/domains/session/sync/global-queue-drainer.ts","lineNumber":117,"sourceCode":"  const sendVariant = sessionModelSelection ? sessionModelSelection.variant : context.variant;\n  const opencodeClient = createClient(\n    context.opencodeBaseUrl,\n    context.workspaceRoot || undefined,\n    { token: context.openworkToken, mode: \"openwork\" },\n  );\n\n  if (draft.mode === \"shell\") {\n    await shellInSession(opencodeClient, sessionId, text);\n    return;\n  }\n\n  if (draft.command) {\n    const result = await opencodeClient.session.command({\n      sessionID: sessionId,\n      command: draft.command.name,\n      arguments: draft.command.arguments,\n    });\n    if (result.error) throw new Error(serializeSDKError(result.error));\n    return;\n  }\n\n  const parts = await draftToParts(draft, context.workspaceRoot, sessionId, {\n    client: context.client,\n    workspaceId: context.workspaceId,\n  });\n  const envSystemContext = await buildOpenworkEnvSystemContext(context.client, {\n    cacheKey: sessionId,\n    runtimeKey: context.environmentRuntimeKey,\n  });\n  const result = await opencodeClient.session.promptAsync({\n    sessionID: sessionId,\n    parts,\n    model: sendModel ?? undefined,\n    agent: context.agent ?? undefined,\n    ...(sendVariant ? { variant: sendVariant } : {}),\n    ...(envSystemContext ? { system: envSystemContext } : {}),","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/react-app/domains/session/sync/global-queue-drainer.ts#L99-L135","documentation":"In performQueuedDraftSend, when a queued draft is a slash-command draft, the app calls opencodeClient.session.command and checks the SDK result. If the OpenCode SDK returns an `error` field on an otherwise-resolved response, the code wraps it via serializeSDKError and throws. This means the server accepted the HTTP request but rejected the command execution (bad session, unknown command, invalid arguments, or server-side failure).","triggerScenarios":"Draining the global draft queue while the target session no longer exists, the command name/arguments are stale or invalid, or the openwork/opencode server returns a structured error payload for session.command.","commonSituations":"Queued drafts persisted before a session was deleted or after a server restart; typo'd or renamed custom commands; command arguments failing server-side validation; server temporarily unhealthy while the queue drains in the background.","solutions":["Inspect the serialized error text to see the SDK's error code/message and fix the underlying cause (e.g. recreate the session or correct the command).","Verify the sessionID is still valid: fetch the session via the client before draining or drop drafts whose session is gone.","Validate command name and arguments against the server's command registry before enqueueing.","Confirm the openwork/opencode server is running and reachable; retry the drain after connectivity is restored."],"exampleFix":"// before\nif (result.error) throw new Error(serializeSDKError(result.error));\n// after\nif (result.error) {\n  const msg = serializeSDKError(result.error);\n  if (isSessionNotFound(result.error)) {\n    await discardDraft(draft.id); // stale draft, don't crash the drain\n    return;\n  }\n  throw new Error(`Command \"${draft.command.name}\" failed: ${msg}`);\n}","handlingStrategy":"try-catch","validationCode":"const session = await opencodeClient.session.get({ sessionID: sessionId });\nif (!session.data) throw new Error(`Session ${sessionId} no longer exists; discard queued draft`);","typeGuard":"function hasCommand(draft: Draft): draft is Draft & { command: { name: string; arguments: Record<string, string> } } {\n  return typeof draft.command?.name === \"string\" && draft.command.name.length > 0;\n}","tryCatchPattern":"try {\n  await performQueuedDraftSend(draft, context);\n} catch (err) {\n  if (String(err.message).includes(\"session\")) await discardDraft(draft.id);\n  else await requeueWithBackoff(draft, err);\n}","preventionTips":["Validate command names against the server registry at enqueue time","Prune queue drafts whose session no longer exists before draining","Drain with retry/backoff instead of letting one failure abort the whole queue"],"tags":["sdk-error","session-command","queue-drain","network"],"backgroundTag":"sdk-error-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}