paperclipai/paperclip · error · Error
request.session.provider must match request.provider
Error message
request.session.provider must match request.provider
What it means
parseEvalSessionRequest requires that when request.session.provider is supplied it must exactly equal the top-level request.provider (eval-session-contract.ts:291-293). The session block is the CreateCapabilityLiveSessionInput forwarded to CapabilityLiveSessionService, and a mismatch would mean the live session runs on a different agent provider than the eval request declares. The guard is fail-closed: omit session.provider to inherit the top-level value, or keep the two identical.
Source
Thrown at packages/paperclip-runner/src/cli/eval-session-contract.ts:301
throw new Error("request.runnerd.sha256 must be a SHA-256 digest");
}
const limits = object(input.limits, "request.limits");
const sessionInput = object(input.session, "request.session");
const session = sessionInput as unknown as CreateCapabilityLiveSessionInput;
const model = text(input.model, "request.model");
if (provider === "claude_managed" && model !== "claude-sonnet-5") {
throw new Error("Claude Managed evals require exact model claude-sonnet-5");
}
if (
provider === "aws_agentcore" &&
model !== "global.anthropic.claude-sonnet-4-6"
) {
throw new Error(
"AWS AgentCore evals require exact model global.anthropic.claude-sonnet-4-6",
);
}
if (sessionInput.provider !== undefined && sessionInput.provider !== provider) {
throw new Error("request.session.provider must match request.provider");
}
if (
session.requestedModel !== undefined &&
session.requestedModel !== model
) {
throw new Error("request.session.requestedModel must match request.model");
}
if (session.acpxAgent === "pi") {
throw new Error("The Pi ACPX profile is not available");
}
return {
schema: EVAL_SESSION_REQUEST_SCHEMA,
attemptId: text(input.attemptId, "request.attemptId"),
prompt: text(input.prompt, "request.prompt"),
model,
provider,
driver,View on GitHub (pinned to 01ad858492)
Solutions
- Set request.session.provider to the same value as request.provider, or delete request.session.provider entirely so it defaults to the top-level provider.
- Search the request JSON for "session" and verify every mirrored field (provider, requestedModel) matches the top-level request fields.
- Regenerate the request from the tooling that pairs provider and session together instead of editing by hand.
- If this happens programmatically, fix the code that builds CreateCapabilityLiveSessionInput to derive session.provider from the same variable used for request.provider.
Example fix
// before
{
"provider": "codex",
"session": { "provider": "opencode", ... }
}
// after
{
"provider": "codex",
"session": { "provider": "codex", ... }
}
// or simply remove session.provider to inherit it Defensive patterns
Strategy: validation
Validate before calling
function assertSessionProviderMatches(req: { provider?: string; session?: { provider?: string } }): void {
if (req.session?.provider !== undefined && req.session.provider !== req.provider) {
throw new Error(`session.provider (${req.session.provider}) != provider (${req.provider})`);
}
} Type guard
function hasConsistentProvider(req: { provider?: string; session?: { provider?: string } }): boolean {
return req.session?.provider === undefined || req.session.provider === req.provider;
} Try / catch
try {
const parsed = parseEvalSessionRequest(rawRequest);
// proceed
} catch (err) {
if (err instanceof Error && err.message === "request.session.provider must match request.provider") {
// normalize: delete session.provider or set it from top-level provider, then retry
} else throw err;
} Prevention
- Build the session object from the same provider variable used at the top level — never duplicate the literal.
- Prefer omitting session.provider; it inherits request.provider.
- Diff generated request JSONs against a checked-in golden template in CI.
- After any provider migration, grep request fixtures for the old provider string.
When it happens
Trigger: Submitting an eval-session request where request.provider is e.g. 'codex' but request.session.provider is 'opencode', 'claude_managed', 'acpx', or any other string (including undefined-vs-typo differences like 'claude_managed' vs 'claude-managed').
Common situations: Hand-editing one field of the request JSON and not the nested session block; copying a session object from a request built for a different provider; template/stale request files after a provider migration.
Related errors
- request.session.requestedModel must match request.model
- AWS AgentCore evals require exact model global.anthropic.cla
- ${label} is not a regular file at ${canonical}.
- Claude Managed evals require exact model claude-sonnet-5
- Report campaign ID does not match publication target
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-02).
Data as JSON: /api/errors/8dd3102dd573d4b8.
Report an issue: GitHub.