vercel/ai · error · InvalidArgumentError
Invalid argument for parameter batch: batch must be a suppor
Error message
Invalid argument for parameter batch: batch must be a supported text batch reference
What it means
When lifecycle state records a bridge sandboxId, validateACPLifecycleCompatibility verifies it matches the sandboxId of the session being created. A mismatch means the state belongs to a different sandbox (machine/container) than the one this harness is attached to, so resume is rejected to avoid operating on the wrong sandbox.
Source
Thrown at packages/ai/src/batch/batch.ts:284
parameter: 'requests',
value: requests,
message: `request IDs must be unique; duplicate ID "${request.id}"`,
});
}
ids.add(request.id);
}
}
function validateBatchReference({
model,
batch,
}: {
model: BatchLanguageModelV4;
batch: BatchReference;
}) {
if (batch.version !== 1 || batch.type !== 'text') {
throw new InvalidArgumentError({
parameter: 'batch',
value: batch,
message: 'batch must be a supported text batch reference',
});
}
if (batch.provider !== model.provider || batch.modelId !== model.modelId) {
throw new InvalidArgumentError({
parameter: 'model',
value: model,
message:
`model ${model.provider}:${model.modelId} is not compatible with ` +
`batch ${batch.provider}:${batch.modelId}`,
});
}
}
async function convertBatchItemResult(View on GitHub (pinned to 69428b1f8b)
Solutions
- Attach to the sandbox whose id matches lifecycleData.bridge.sandboxId.
- If the original sandbox is gone, start a fresh session instead of resuming the state.
- Copy/persist state per sandbox and key it by sandboxId to avoid cross-sandbox reuse.
Example fix
// before
createACPV1({ sandbox: sandboxNew, lifecycle: stateFromSandboxOld })
// after
const sandbox = await connectToSandbox({ id: state.bridge.sandboxId });
createACPV1({ sandbox, lifecycle: stateFromSandboxOld }) Defensive patterns
Strategy: validation
Validate before calling
const expected = lifecycleData.bridge?.sandboxId;
if (expected != null && sandbox.id != null && expected !== sandbox.id) {
throw new Error(`Lifecycle state belongs to sandbox ${expected}, not ${sandbox.id}`);
} Try / catch
try {
harness = createACPV1({ sandbox, lifecycle: state });
} catch (error) {
if (error instanceof Error && error.message.includes('belongs to sandbox')) {
// original sandbox is gone or different: start a fresh session
harness = createACPV1({ sandbox });
} else {
throw error;
}
} Prevention
- Persist lifecycle state per sandboxId and look it up by the sandbox you attach to.
- Detect sandbox recreation (new id) and invalidate saved lifecycle state.
- Avoid sharing session state between dev/staging/prod sandboxes.
When it happens
Trigger: Calling createACPV1 with a sandbox session whose id differs from lifecycleData.bridge.sandboxId; reattaching lifecycle state to a newly created sandbox; pointing the harness at a different sandbox environment after the original one expired or was replaced.
Common situations: A sandbox was restarted or recreated (new sandbox id) while the old lifecycle state was kept; connecting to a teammate's or another environment's sandbox; reusing saved state across dev/staging sandboxes.
Related errors
- Invalid argument for parameter requests: requests must not b
- Invalid argument for parameter requests: request IDs must no
- Invalid argument for parameter requests: request IDs must be
- Recovered ACP session is disposed.
- SandboxChannel: cannot open a closed channel.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/cedb3b62ba2317f1.
Report an issue: GitHub.