vercel/ai · error · CodeModeProtocolError

CODE_MODE_PROTOCOL_ERROR

CODE_MODE_PROTOCOL_ERROR

Error message

Code mode approval response is malformed.

What it means

This CodeModeProtocolError is thrown by assertCodeModeApprovalResponse when the value passed as an approval response fails structural validation. A valid response must be a non-null, non-array object with a string `approvalId`, a boolean `approved`, and an optional string `reason`. The library throws this to enforce the code-mode approval protocol contract, since an unexpected shape would silently corrupt the approval workflow.

Source

Thrown at packages/code-mode/src/approval.ts:31

  payload: CodeModeInterruptPayload,
): payload is CodeModeApprovalInterruptPayload {
  return payload.kind === CODE_MODE_TOOL_APPROVAL_KIND;
}

export function assertCodeModeApprovalResponse(
  value: unknown,
): asserts value is CodeModeApprovalResponse {
  if (
    typeof value !== 'object' ||
    value === null ||
    Array.isArray(value) ||
    typeof (value as { approvalId?: unknown }).approvalId !== 'string' ||
    typeof (value as { approved?: unknown }).approved !== 'boolean' ||
    ('reason' in value &&
      (value as { reason?: unknown }).reason !== undefined &&
      typeof (value as { reason?: unknown }).reason !== 'string')
  ) {
    throw new CodeModeProtocolError(
      'Code mode approval response is malformed.',
    );
  }
}

export function normalizeApprovalResolution(
  resolution: unknown,
): CodeModeApprovalResolution {
  if (
    typeof resolution !== 'object' ||
    resolution === null ||
    Array.isArray(resolution) ||
    typeof (resolution as { approved?: unknown }).approved !== 'boolean' ||
    ('reason' in resolution &&
      (resolution as { reason?: unknown }).reason !== undefined &&
      typeof (resolution as { reason?: unknown }).reason !== 'string')
  ) {
    throw new CodeModeProtocolError(

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Log the offending value and verify it has string `approvalId`, boolean `approved`, and optional string `reason`
  2. Ensure you build the response from the interrupt payload's actual `approvalId` rather than a hardcoded/renamed field
  3. Check that the value is not null, undefined, or an array before calling continueCodeModeApproval
  4. Validate the response shape (e.g. with a schema or type guard) before passing it in

Example fix

// before
await continueCodeModeApproval({ approvalId: payload.id, approved: 'yes' });
// after
await continueCodeModeApproval({
  approvalId: payload.approvalId,
  approved: true,
  reason: 'user clicked allow',
});
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidApprovalResponse(v: unknown): boolean {
  return (
    typeof v === 'object' && v !== null && !Array.isArray(v) &&
    typeof (v as any).approvalId === 'string' &&
    typeof (v as any).approved === 'boolean' &&
    (!('reason' in v) || (v as any).reason === undefined || typeof (v as any).reason === 'string')
  );
}
if (!isValidApprovalResponse(response)) throw new Error('invalid approval response');

Type guard

function isCodeModeApprovalResponse(v: unknown): v is CodeModeApprovalResponse {
  return (
    typeof v === 'object' && v !== null && !Array.isArray(v) &&
    typeof (v as { approvalId?: unknown }).approvalId === 'string' &&
    typeof (v as { approved?: unknown }).approved === 'boolean' &&
    (!('reason' in v) || (v as { reason?: unknown }).reason === undefined || typeof (v as { reason?: unknown }).reason === 'string')
  );
}

Try / catch

import { CodeModeProtocolError } from '.../errors.js';
try {
  await continueCodeModeApproval(response);
} catch (error) {
  if (CodeModeProtocolError.isInstance(error)) {
    console.error('Malformed approval response:', response);
    return; // reject or re-prompt the user
  }
  throw error;
}

Prevention

When it happens

Trigger: Passing a malformed object to continueCodeModeApproval: missing `approvalId`, wrong type (e.g. numeric id), missing or non-boolean `approved`, `reason` present but not a string, passing null/undefined, or passing an array. Also occurs when forwarding a deserialized/persisted response (e.g. from JSON in a queue or DB) whose shape changed between serialization points.

Common situations: Manually constructing a response object in a custom UI approval handler; storing approval responses in a database and reading back old/renamed field names; deserializing responses over HTTP where types were coerced (approved: "true"); upgrading SDK versions where the response schema gained/renamed fields.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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