vercel/ai · error

Open Responses extension ${extension.id} cannot provide enco

Error message

Open Responses extension ${extension.id} cannot provide encodeInputItem without itemTypes and decodeItem.

What it means

encodeInputItem lets an extension encode input items of a custom type, but it requires the decoding side (itemTypes + decodeItem) to exist so the item type is registered and understood. The registry rejects encodeInputItem alone.

Source

Thrown at packages/open-responses/src/open-responses-extension.ts:221

      });
      registerUnique({
        map: registry.byToolType,
        key: toolExtension.toolType,
        extension: toolExtension,
        field: 'toolType',
      });
    }

    const hasItemTypes = extension.itemTypes != null;
    const hasItemDecoder = extension.decodeItem != null;
    if (hasItemTypes !== hasItemDecoder) {
      throw new Error(
        `Open Responses extension ${extension.id} must provide itemTypes and decodeItem together.`,
      );
    }

    if (extension.encodeInputItem != null && !hasItemDecoder) {
      throw new Error(
        `Open Responses extension ${extension.id} cannot provide encodeInputItem without itemTypes and decodeItem.`,
      );
    }

    if (hasItemTypes && hasItemDecoder) {
      const itemExtension = extension as OpenResponsesItemExtension;
      if (itemExtension.itemTypes.length === 0) {
        throw new Error(
          `Open Responses extension ${extension.id} must register at least one item type.`,
        );
      }
      for (const itemType of itemExtension.itemTypes) {
        assertNamespacedType({
          extensionId: extension.id,
          namespace,
          type: itemType,
          field: 'itemTypes',
        });

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Add itemTypes and decodeItem to the extension alongside encodeInputItem.
  2. Remove encodeInputItem if the extension should not handle input items.
  3. Define the extension against the OpenResponsesItemExtension interface for compile-time safety.

Example fix

// before
{ id: 'acme.ticket', encodeInputItem: (item) => ({...}) }
// after
{ id: 'acme.ticket', itemTypes: ['ticket'], decodeItem: decodeTicket, encodeInputItem: (item) => ({...}) }
Defensive patterns

Strategy: validation

Validate before calling

extensions.forEach(e => {
  const x = e as any;
  if (x.encodeInputItem != null && (x.itemTypes == null || x.decodeItem == null)) {
    throw new Error(`${x.id}: encodeInputItem requires itemTypes and decodeItem`);
  }
});

Type guard

function canEncodeInputItem(e: object): boolean {
  const x = e as any;
  return x.encodeInputItem == null || (x.itemTypes != null && x.decodeItem != null);
}

Try / catch

try {
  const registry = createOpenResponsesExtensionRegistry(extensions);
} catch (e) {
  if (e instanceof Error && e.message.includes('cannot provide encodeInputItem without itemTypes and decodeItem')) {
    // add the decoder pair or remove encodeInputItem
  }
  throw e;
}

Prevention

When it happens

Trigger: Registering an extension with encodeInputItem defined while itemTypes/decodeItem are absent.

Common situations: Writing an input-side-only extension assuming the registry will infer types; trimming a full item extension and accidentally keeping encodeInputItem; refactoring that removed the decoder but not the encoder.

Related errors


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