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
- Add itemTypes and decodeItem to the extension alongside encodeInputItem.
- Remove encodeInputItem if the extension should not handle input items.
- 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
- Implement encoders and decoders for an item type together, never separately.
- Use the OpenResponsesItemExtension interface so TS requires the full set.
- Add a registry-construction smoke test per extension.
- Keep custom item codecs in one module so halves cannot diverge.
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
- Open Responses extension ID ${extension.id} must use <implem
- Open Responses extension ${extension.id} must provide toolTy
- Open Responses extension ${extension.id} cannot provide enco
- Open Responses extension ${extension.id} must provide itemTy
- maxEmbeddingsPerCall must be greater than 0
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/e12ca238b1c299cb.
Report an issue: GitHub.