Profiles·Public

@anthropic-ai/claude-agent-sdk

semver>=0.1.0postconditions25functions14last verified2026-06-24coverage score85%

Postconditions: what we check

  • query · query-abort-error
    error
    Whenquery() is called with an abortController option and the controller is aborted during execution (e.g., user cancels the session), but the `for await` loop is not wrapped in a try/catch block.
    ThrowsAbortError
    Required handlingWrap the `for await (const message of query(...))` loop in a try/catch block. Check if the error is an AbortError (error.name === 'AbortError' or error instanceof AbortError) to distinguish intentional cancellation from unexpected failures. Intentional aborts should be handled gracefully, not re-thrown as errors.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • query · query-network-process-error
    error
    Whenquery() is called without a try/catch around the `for await` loop, and the underlying Claude process fails to start or encounters a network/process error during execution.
    ThrowsError
    Required handlingWrap both the query() call itself AND the `for await` loop in separate try/catch blocks. The query() call can throw synchronously if configuration is invalid. The `for await` loop can throw on process-level failures. Log errors with context (duration, stderr) for debugging.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • query · query-result-error-subtype-unchecked
    error
    WhenThe `for await` loop processes messages from query() but only reads `message.result` without checking `message.subtype`. When the agent hits max turns, exhausts the budget, or encounters execution errors, the loop emits an SDKResultError (type: 'result', subtype: 'error_during_execution' | 'error_max_turns' | 'error_max_budget_usd' | 'error_max_structured_output_retries') — but `message.result` is undefined on the error variant, and `message.errors` contains the actual failure reason. Code that accesses `message.result` directly reads undefined, silently returning no output.
    ThrowsSDKResultError (type: 'result', subtype: 'error_*') — not thrown but emitted as a message
    Required handlingAlways check message.subtype before accessing message.result: if (message.type === 'result') { if (message.subtype === 'success') { console.log(message.result); } else { // error_during_execution | error_max_turns | error_max_budget_usd console.error('Agent failed:', message.errors); throw new Error(`Agent error: ${message.subtype}: ${message.errors.join('; ')}`); } } The SDKResultError shape has no `result` field — only `errors: string[]`. Callers that do `if ('result' in message) ...` will silently skip the error.
    costhighin prodsilent failureusers seelost datavisibilitysilent
    Sources[2]
  • query · query-assistant-message-error-unchecked
    error
    WhenThe `for await` loop processes SDKAssistantMessage objects but does not check the optional `error` field. When the Anthropic API returns an error mid-stream (authentication_failed, billing_error, rate_limit, server_error, max_output_tokens), the assistant message's `error` field is set to one of those string literals. The message is still emitted with an empty/partial content block — callers that don't check `error` display corrupt output and continue as if the turn succeeded.
    ThrowsSDKAssistantMessageError: 'authentication_failed' | 'billing_error' | 'rate_limit' | 'invalid_request' | 'server_error' | 'unknown' | 'max_output_tokens'
    Required handlingCheck the error field on assistant messages: if (message.type === 'assistant' && message.error) { switch (message.error) { case 'authentication_failed': throw new Error('API key invalid or revoked'); case 'billing_error': throw new Error('Account billing issue — check Anthropic Console'); case 'rate_limit': // Implement backoff and retry break; case 'max_output_tokens': // Increase maxTokens or break the task into smaller subtasks break; default: throw new Error(`API error: ${message.error}`); } } Without this check, a billing_error or auth failure silently produces empty agent output that looks like a successful empty response.
    costhighin prodsilent failureusers seelost datavisibilitysilent
    Sources[2]
  • startup · startup-timeout-uncaught
    error
    Whenstartup() is called without a try/catch or .catch() handler, and the Claude CLI subprocess fails to initialize within initializeTimeoutMs (default 60 seconds). This happens when the CLI binary is missing, the process cannot be spawned (permissions, PATH issues), or the machine is under heavy load.
    ThrowsError (timeout — "initialization did not complete in time")
    Required handlingWrap startup() in a try/catch and handle the timeout explicitly: try { const warm = await startup({ initializeTimeoutMs: 30000 }); const result = warm.query(prompt); // ... process result } catch (err) { if (err.message?.includes('timeout') || err.message?.includes('initialization')) { // Fall back to cold-start query() or surface error to user console.error('Agent startup timed out:', err.message); } throw err; } If startup() is called once at application start in a background job, an unhandled rejection crashes the Node.js process silently.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • startup · startup-warm-query-not-disposed
    warning
    Whenstartup() resolves successfully, but the WarmQuery handle is never used (warm.query() is never called) and is also never closed via warm.close() or `using warm = await startup(...)`. WarmQuery implements AsyncDisposable. An unclosed WarmQuery leaves the subprocess running and blocks clean process exit.
    ThrowsNo thrown error — subprocess leak, process hangs on exit
    Required handlingAlways either use or close the WarmQuery: // Option 1: Use it immediately const warm = await startup(); const result = warm.query(prompt); // consumes the warm query // Option 2: Use `using` for automatic disposal (TypeScript 5.2+) await using warm = await startup(); const result = warm.query(prompt); // Option 3: Close explicitly if not needed const warm = await startup(); if (!needsAgent) { warm.close(); return; } A leaked WarmQuery in a serverless function prevents the invocation from completing — the function times out and incurs full execution cost.
    costmediumin proddelayed failureusers seeservice unavailablevisibilityvisible
    Sources[2]
  • forkSession · fork-session-not-found
    error
    WhenforkSession() is called with a sessionId that doesn't exist in the project directory. The session file may have been deleted, or the calling process is using a different cwd than the process that created the session. Sessions are stored at: ~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl where encoded-cwd replaces non-alphanumeric chars with '-'. A cwd mismatch causes a "session not found" failure.
    ThrowsError (session file not found / ENOENT)
    Required handlingWrap forkSession() in a try/catch and verify the sessionId before calling: try { const { sessionId: forkId } = await forkSession(originalSessionId); } catch (err) { if (err.code === 'ENOENT' || err.message?.includes('not found')) { console.error('Session not found — cwd mismatch or file deleted:', err); // Cannot fork; start a fresh session instead } else { throw err; } } The docs explicitly warn: if a resume call returns a fresh session, the most common cause is a cwd mismatch. The same applies to forkSession.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • renameSession · rename-session-empty-title
    warning
    WhenrenameSession() is called with a title that is empty or whitespace-only (e.g., '', ' '). The documentation states the title "must be non-empty after trimming whitespace." An empty title throws a validation error. This commonly occurs when user input is passed directly without validation.
    ThrowsError (validation — title must be non-empty after trimming)
    Required handlingValidate the title before calling renameSession(): const trimmedTitle = title.trim(); if (!trimmedTitle) { throw new Error('Session title cannot be empty'); } await renameSession(sessionId, trimmedTitle); Without this guard, passing an empty string from a UI form throws an unhandled error that surfaces to the user as an unhandled rejection.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • tagSession · tag-session-not-found
    warning
    WhentagSession() is called with a sessionId that does not exist on the local filesystem, or the cwd doesn't match the directory where the session was created. The function writes to the session's JSONL file and will throw a filesystem error if the file is not found.
    ThrowsError (ENOENT — session file not found)
    Required handlingVerify the session exists before tagging, or catch the error: try { await tagSession(sessionId, tag); } catch (err) { if (err.code === 'ENOENT') { console.warn('Session not found for tagging:', sessionId); } else { throw err; } }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • unstable_v2_prompt · v2-prompt-result-error-unchecked
    error
    Whenunstable_v2_prompt() is called and the returned SDKResultMessage is accessed directly without checking result.subtype. SDKResultMessage is a discriminated union: SDKResultSuccess (subtype: 'success', has result: string field) and SDKResultError (subtype: 'error_during_execution' | 'error_max_turns' | 'error_max_budget_usd' | 'error_max_structured_output_retries', no result field, has errors: string[] field). When Claude hits max turns, budget limits, or execution errors, the promise resolves with SDKResultError — not rejected. Code that reads result.result directly gets undefined silently.
    ThrowsSDKResultError (type: 'result', subtype: 'error_*') — promise resolves (not rejected) with an error-variant result. result.result is undefined on error variant.
    Required handlingAlways check result.subtype before reading result.result: const result = await unstable_v2_prompt("prompt", { model: '...' }); if (result.subtype === 'success') { console.log(result.result); } else { // result.subtype is 'error_during_execution', 'error_max_turns', // 'error_max_budget_usd', or 'error_max_structured_output_retries' console.error('Agent failed:', result.errors); }
    costmediumin prodsilent failureusers seelost datavisibilitysilent
    Sources[4]
  • unstable_v2_prompt · v2-prompt-no-try-catch
    error
    Whenunstable_v2_prompt() is called without a try/catch block, and the underlying Claude subprocess fails to start (e.g., native binary missing, process crash) or the response stream terminates without a result message. The SDK source throws Error("Session ended without result message") if the stream ends without a result-type message. AbortError is thrown if the operation is aborted. Native binary missing throws Error("Native CLI binary for <platform>-<arch> not found. Reinstall @anthropic-ai/claude-agent-sdk without --omit=optional").
    ThrowsError (session ended without result) | AbortError (if aborted) | Error (native binary missing)
    Required handlingWrap unstable_v2_prompt() in a try/catch: try { const result = await unstable_v2_prompt("prompt", { model: '...' }); if (result.subtype === 'success') { return result.result; } else { throw new Error(`Agent failed: ${result.errors.join(', ')}`); } } catch (error) { if (error.name === 'AbortError') { // Handle intentional cancellation } else { // Handle subprocess/process errors throw error; } }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • unstable_v2_prompt · v2-session-not-closed
    warning
    WhenAn SDKSession created by unstable_v2_createSession() is used without closing it via session.close(), `await using`, or Symbol.asyncDispose. SDKSession wraps a Claude subprocess — if not closed, the subprocess continues running until the Node.js process exits. In long-running services, each unclosed session leaks a subprocess. The V2 docs explicitly recommend `await using` (TypeScript 5.2+) for automatic cleanup.
    ThrowsNo throw — leaked subprocess runs silently in background. Visible as process accumulation in `ps aux` or resource exhaustion on the host.
    Required handlingUse `await using` for automatic cleanup (TypeScript 5.2+): await using session = unstable_v2_createSession({ model: '...' }); // session.close() called automatically on scope exit Or call session.close() explicitly in a finally block: const session = unstable_v2_createSession({ model: '...' }); try { await session.send("Hello"); for await (const msg of session.stream()) { ... } } finally { session.close(); }
    costmediumin proddegraded serviceusers seedegraded performancevisibilitysilent
    Sources[4]
  • deleteSession · delete-session-not-found
    error
    WhendeleteSession() is called without a try/catch and the sessionId does not exist in the configured project directory. This happens routinely in cleanup paths (UI delete button, retention sweeper, test teardown) when the session was already deleted by another process, when the caller is using a different cwd than the session creator (so the encoded project key doesn't match), or when the session id was stored as state but the underlying JSONL was manually purged.
    ThrowsError (message: "Session {sessionId} not found in project directory for {dir}" / "Session {sessionId} not found in any project directory")
    Required handlingWrap deleteSession() in try/catch and treat "not found" as a benign terminal state (idempotent delete), rejecting only on truly unexpected errors: try { await deleteSession(sessionId, { dir: projectDir }); } catch (err) { if (err.message?.includes('not found')) { // Already gone — idempotent delete succeeded return; } throw err; } Without this guard, a "delete" button that runs twice (double-click, retry on transient error) surfaces a confusing "session not found" error to the user despite the delete having actually succeeded the first time.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3][5]
  • deleteSession · delete-session-invalid-uuid
    warning
    WhendeleteSession() is called with a sessionId that is not a valid UUID. The SDK validates sessionId format before touching the filesystem and throws `Error("Invalid sessionId: ${e}")`. Commonly happens when a truncated id, a placeholder string ("undefined", ""), or an id from a different SDK (claude-code CLI vs claude-agent-sdk) is passed through.
    ThrowsError (message: "Invalid sessionId: {value}")
    Required handlingValidate the sessionId before calling deleteSession(), or treat the UUID validation error as a non-retryable input error: const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (!UUID_RE.test(sessionId)) { throw new BadRequest(`Invalid sessionId: ${sessionId}`); } try { await deleteSession(sessionId); } catch (err) { if (err.message?.startsWith('Invalid sessionId')) { throw new BadRequest(err.message); } throw err; } Unhandled, this surfaces as a 500 error on a delete endpoint when it should be a 400 — confusing operators who think the SDK is broken.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • importSessionToStore · import-session-partial-failure
    error
    WhenimportSessionToStore() is called without a try/catch, and the SessionStore.append() implementation throws partway through the batch upload. Because entries are appended in batches (default batchSize), an error on batch N leaves entries from batches 1..N-1 successfully written to the store while batches N..end are not. The function rejects with the underlying store error, but the partial state in the store is NOT rolled back.
    ThrowsError (whatever the SessionStore.append() implementation throws — network error, auth failure, quota exceeded, etc.)
    Required handlingWrap importSessionToStore() in try/catch AND track which sessions have been fully migrated vs partially migrated. Do NOT assume a retry will be idempotent unless the store's append() is idempotent on duplicate entry ids: const migrated: string[] = []; const partial: { sessionId: string; error: string }[] = []; for (const sessionId of toMigrate) { try { await importSessionToStore(sessionId, store, { batchSize: 100 }); migrated.push(sessionId); } catch (err) { partial.push({ sessionId, error: err.message }); // Mark as partial — needs cleanup before retry } } Without this guard, a migration script that retries on failure will append duplicate entries to the store, corrupting the session transcript.
    costhighin prodsilent failureusers seelost datavisibilitysilent
    Sources[5]
  • importSessionToStore · import-session-source-missing
    warning
    WhenimportSessionToStore() is called without a try/catch and the source JSONL session file does not exist on disk in the (resolved or searched) project directory. The session file may have been deleted by an earlier deleteSession() call, the calling process may be running with a different cwd, or the sessionId may be wrong. The SDK throws the same "Session not found" error class as deleteSession()/getSessionInfo().
    ThrowsError (message: "Session {sessionId} not found in project directory for {dir}" / "Session {sessionId} not found in any project directory")
    Required handlingWrap importSessionToStore() in try/catch and either (a) skip missing sessions in a migration loop, or (b) surface the missing session as a data integrity warning to the operator: try { await importSessionToStore(sessionId, store, { dir: projectDir }); } catch (err) { if (err.message?.includes('not found')) { // Source session was deleted between listSessions() and import console.warn(`Skipping missing session ${sessionId}`); continue; } throw err; }
    costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible
    Sources[5]
  • resolveSettings · resolve-settings-subprocess-failure
    error
    WhenresolveSettings() is called without a try/catch in an environment where the MDM subprocess (`plutil` on macOS, `reg.exe` on Windows) fails to spawn or returns an error. This happens in sandboxed environments (containers, AppArmor, SELinux), in CI runners that strip $PATH, on macOS with locked-down configurations, and when the user lacks permission to read the MDM plist. The SDK propagates the underlying spawn / non-zero-exit error.
    ThrowsError (subprocess spawn failure / non-zero exit from plutil or reg.exe)
    Required handlingWrap resolveSettings() in try/catch and fall back to a sensible default settings object when MDM resolution fails: let settings; try { settings = await resolveSettings({ cwd, sources: ['user', 'project', 'local'] }); } catch (err) { console.warn('Settings resolution failed, using defaults:', err.message); settings = DEFAULT_SETTINGS; } Or skip MDM by passing `sources: []` or an explicit subset to avoid the subprocess paths entirely. Without this guard, self-hosted CI pipelines running the SDK crash on startup with an inscrutable spawn error.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • resolveSettings · resolve-settings-default-mode-not-filtered
    error
    WhenresolveSettings() succeeds and the caller reads `settings.permissions.defaultMode` directly without first passing it through `filterEscalatingDefaultMode()`. The SDK explicitly documents that `permissions.defaultMode` is reported as-is across all tiers including project — but the CLI applies a separate trust filter before honoring escalating modes (`bypassPermissions`, `auto`, `acceptEdits`) from repo-committed files. Acting on the raw value gives a malicious .claude/settings.json in a cloned repo the ability to escalate permissions silently.
    ThrowsNo throw — silent security bypass. A repo-committed defaultMode of 'bypassPermissions' is honored by the caller despite the trust filter.
    Required handlingAlways pass the resolved settings through filterEscalatingDefaultMode() before reading defaultMode: const resolved = await resolveSettings({ cwd }); const safe = filterEscalatingDefaultMode(resolved); const mode = safe.permissions?.defaultMode ?? 'default'; // Use `mode` — guaranteed not to be a repo-injected escalation The CLI does this filtering internally; SDK consumers that replicate the resolution path MUST replicate the filter too.
    costhighin prodsilent failureusers seesecurity breachvisibilitysilent
    Sources[5]
  • listSessions · list-sessions-store-method-missing
    error
    WhenlistSessions() is called with a `sessionStore` option but the provided store does NOT implement the optional `listSessions(projectKey)` method. The SessionStore interface declares `listSessions?` as optional — many partial implementations (especially append-only or WORM stores) omit it. Without the method, listSessions() rejects with a TypeError or "store does not support listing" error.
    ThrowsTypeError ("store.listSessions is not a function") | Error (store-specific "not supported")
    Required handlingEither feature-detect the store before calling, or wrap the call in try/catch: if (typeof store.listSessions === 'function') { const sessions = await listSessions({ sessionStore: store, dir: cwd }); } else { // Fall back to filesystem path or surface a clear error const sessions = await listSessions({ dir: cwd }); } Or: try { const sessions = await listSessions({ sessionStore: store }); } catch (err) { if (err instanceof TypeError && err.message.includes('listSessions')) { // store does not support listing — degrade gracefully return []; } throw err; } Without this guard, swapping in a partial SessionStore implementation (common during migration from local FS to a remote backend) crashes every list-sessions call with an unhandled rejection.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • listSessions · list-sessions-empty-result-unchecked
    warning
    WhenlistSessions() returns an empty array when the project directory contains no session files, when the cwd doesn't match the encoded-project-key the SDK derives, or when the `~/.claude/projects/` root doesn't exist yet. Callers that index the result directly (`sessions[0].sessionId`, `sessions.length > 0` short-circuit removed) read undefined silently. This commonly breaks "resume last session" UX where the caller assumes at least one session exists.
    ThrowsNo throw — silent empty-result. Caller reading sessions[0].sessionId throws TypeError downstream.
    Required handlingAlways check the length before indexing, and provide a fallback for the empty case: const sessions = await listSessions({ dir: cwd, limit: 1 }); if (sessions.length === 0) { // Start a fresh session instead of resuming return startFreshSession(); } const latest = sessions[0]; A "resume last session" CLI that crashes on first-run (no sessions yet) instead of starting fresh is a common reported bug.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • getSessionInfo · get-session-info-undefined-unchecked
    warning
    WhengetSessionInfo() is called and the returned value is dereferenced directly without a null/undefined check. Per the JSDoc, undefined is returned in three cases: (1) session file not found, (2) session is a sidechain session, (3) no extractable summary. Code like `(await getSessionInfo(id)).summary` throws TypeError ("Cannot read properties of undefined") at runtime.
    ThrowsTypeError (downstream) — reading a property of undefined
    Required handlingAlways guard the result before accessing fields: const info = await getSessionInfo(sessionId, { dir: projectDir }); if (!info) { // Session missing, sidechain, or no summary — fall back return null; } return info.summary; Or use optional chaining: const summary = (await getSessionInfo(sessionId))?.summary; Treating undefined as "session unavailable" is the documented contract.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • getSessionInfo · get-session-info-store-load-failure
    error
    WhengetSessionInfo() is called with a `sessionStore` option and the store's `load(key)` rejects. Reasons include: network failure (remote store), auth/quota error, corrupted entry, store-specific schema-version mismatch. The SDK does not catch — the rejection propagates to the caller. Treating this as benign (like the undefined ENOENT case) is incorrect: a store load failure means the session MAY exist but cannot currently be read.
    ThrowsError (whatever SessionStore.load() implementation throws — network, auth, etc.)
    Required handlingWrap in try/catch and distinguish "not found" (undefined) from "could not load" (thrown): try { const info = await getSessionInfo(sessionId, { sessionStore: store }); if (!info) { // Truly absent — start fresh return null; } return info; } catch (err) { // Transient store failure — retry, don't start fresh console.error('Session lookup failed (transient):', err); throw err; } Conflating "store unreachable" with "session deleted" silently discards user history when callers fall back to "start fresh" on any error.
    costhighin prodimmediate exceptionusers seelost datavisibilityvisible
    Sources[6]
  • getSessionMessages · get-session-messages-empty-vs-thrown
    error
    WhengetSessionMessages() returns an empty array when the session file is missing on disk, OR throws when the underlying transcript is corrupted (malformed JSON line, unparseable timestamp) or when a configured `sessionStore.load()` rejects. Callers that assume "empty means no messages" without a try/catch swallow corruption errors as crashes instead of distinguishing "no history" from "history unreadable."
    ThrowsError (corrupted JSONL line, store load failure) | Returns [] (session not found, sidechain)
    Required handlingWrap in try/catch and treat empty-array as the only successful "no history" signal: try { const messages = await getSessionMessages(sessionId, { dir: projectDir, limit: 100, }); if (messages.length === 0) { // Session truly empty / missing — fall back return []; } return messages; } catch (err) { // Corruption or store failure — DO NOT pretend the session is empty console.error('Session transcript unreadable:', err); throw err; } Treating a thrown error as "no messages" silently discards real user history in a UI — far worse than surfacing the error.
    costmediumin prodimmediate exceptionusers seelost datavisibilityvisible
    Sources[6]
  • listSubagents · list-subagents-store-method-missing
    error
    WhenlistSubagents() is called with a `sessionStore` that does NOT implement the optional `listSubagents` method. Same failure mode as list-sessions-store-method-missing: TypeError when the SDK invokes the undefined method. Common during incremental migration from local FS to a remote-backed SessionStore.
    ThrowsTypeError ("store.listSubagents is not a function")
    Required handlingFeature-detect or wrap in try/catch: try { const ids = await listSubagents(sessionId, { dir: projectDir, sessionStore: store, }); } catch (err) { if (err instanceof TypeError && err.message.includes('listSubagents')) { // Store lacks subagent support — return empty / fall back return []; } throw err; } Without this guard, a subagent-inspection UI panel renders blank and prints an unhandled-rejection in the console.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • getSubagentMessages · get-subagent-messages-empty-vs-thrown
    warning
    WhengetSubagentMessages() returns an empty array when the subagent transcript is missing, OR throws on corrupted JSONL / store load failure (same dual-mode error contract as getSessionMessages). Callers that read `messages.length === 0` without a try/catch silently swallow real corruption as "no history."
    ThrowsError (corrupted JSONL line, store load failure) | Returns [] (subagent not found)
    Required handlingWrap in try/catch and treat empty-array as the only successful "no history" signal: try { const messages = await getSubagentMessages(sessionId, agentId, { dir: projectDir, }); if (messages.length === 0) { return []; } return messages; } catch (err) { console.error('Subagent transcript unreadable:', err); throw err; } Subagent transcripts are often inspected in debugging UIs; conflating "missing" with "unreadable" hides corruption bugs from the developer.
    costlowin prodimmediate exceptionusers seelost datavisibilityvisible
    Sources[6]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
Source code
  • [1]
    unpkg.com/@anthropic-ai/claude-agent-sdk@0.2.91/sdk.d.ts
    Sdk.D.Ts
  • [5]
    unpkg.com/@anthropic-ai/claude-agent-sdk@0.3.174/sdk.d.ts
    Sdk.D.Ts
  • [6]
    unpkg.com/@anthropic-ai/claude-agent-sdk@0.3.187/sdk.d.ts
    Sdk.D.Ts

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources: @anthropic-ai/claude-agent-sdk

Documentation Fetched (2026-04-03)

SDK Type Declarations

README

Official Documentation

Real-World Usage Evidence

CherryHQ/cherry-studio (42k stars)

  • File: src/main/services/agents/services/claudecode/index.ts
  • Pattern: for await (const message of query({ prompt, options })) in try/catch
  • Error handling: Checks errorObj?.name === 'AbortError' explicitly

21st-dev/1code (5k stars)

  • File: src/main/lib/trpc/routers/claude.ts
  • Pattern: Separate try/catch for stream = claudeQuery(queryOptions) and for await (const msg of stream)
  • Error handling: catch (queryError) and catch (streamError) separately

npm Package Info

  • Version: 0.2.91
  • Dependencies: @anthropic-ai/sdk, @modelcontextprotocol/sdk
  • This is the successor to @anthropic-ai/claude-code-sdk
Need a different package?
Request a profile