paperclipai/paperclip · error · RouteError
invalid_provider
invalid_provider
Error message
Provider must be codex, opencode, claude_managed, aws_agentcore, or acpx.
What it means
harnessConfiguration validates the `provider` field of a capability issue-thread request. It must be one of the five supported harness providers — codex (default), opencode, claude_managed, aws_agentcore, or acpx — after trimming. Any other value produces this HTTP 400 RouteError with code invalid_provider.
Source
Thrown at packages/paperclip-runner/scripts/capability-issue-thread-server.mjs:212
startedAt: null,
completedAt: null,
},
],
});
}
class RouteError extends Error {
constructor(status, code, message) {
super(message);
this.status = status;
this.code = code;
}
}
function harnessConfiguration(source, fallbackModel) {
const provider = source.provider === undefined ? "codex" : String(source.provider).trim();
if (provider !== "codex" && provider !== "opencode" && provider !== "claude_managed" && provider !== "aws_agentcore" && provider !== "acpx") {
throw new RouteError(400, "invalid_provider", "Provider must be codex, opencode, claude_managed, aws_agentcore, or acpx.");
}
const rawModel = source.model === undefined ? fallbackModel : source.model;
const model = rawModel === undefined || rawModel === null ? "" : String(rawModel).trim();
if (model.length > 256) throw new RouteError(400, "invalid_model", "Model is too long.");
if (provider === "opencode" && (!model || !model.includes("/"))) {
throw new RouteError(400, "invalid_model", "OpenCode requires a provider/model value.");
}
if (provider === "claude_managed" && model !== "claude-sonnet-5") {
throw new RouteError(400, "invalid_model", "Claude Managed requires exact model claude-sonnet-5.");
}
if (provider === "aws_agentcore" && model !== "global.anthropic.claude-sonnet-4-6") {
throw new RouteError(400, "invalid_model", "AWS AgentCore requires exact model global.anthropic.claude-sonnet-4-6.");
}
const acpxAgent = source.acpxAgent === undefined ? "codex" : String(source.acpxAgent).trim();
if (provider === "acpx") {
if (!(acpxAgent in ACPX_QUALIFIED_MODELS)) {
throw new RouteError(400, "invalid_acpx_agent", "ACPX agent must be claude or codex.");
}View on GitHub (pinned to 5716fe907e)
Solutions
- Set provider to exactly one of: codex, opencode, claude_managed, aws_agentcore, acpx (lowercase).
- Omit provider entirely to use the default "codex".
- Trim whitespace and check casing in the client before sending.
- Update the client/SDK if it still emits a provider name from an older API revision.
Example fix
// before
{ "provider": "Claude-Managed", "model": "claude-sonnet-4-5" }
// after
{ "provider": "claude_managed", "model": "claude-sonnet-4-5" } Defensive patterns
Strategy: validation
Validate before calling
const PROVIDERS = new Set(["codex", "opencode", "claude_managed", "aws_agentcore", "acpx"]);
function assertValidProvider(p) {
const v = p === undefined ? "codex" : String(p).trim();
if (!PROVIDERS.has(v)) throw new Error(`provider must be one of ${[...PROVIDERS].join(", ")}`);
return v;
}
assertValidProvider(requestBody.provider); Type guard
function isHarnessProvider(p) {
return p === undefined || ["codex", "opencode", "claude_managed", "aws_agentcore", "acpx"].includes(p);
} Try / catch
try {
const res = await fetch(url, { method: "POST", body: JSON.stringify(payload) });
if (res.status === 400) {
const body = await res.json();
if (body.code === "invalid_provider") {
// correct the provider client-side and retry once
payload.provider = "codex";
return fetch(url, { method: "POST", body: JSON.stringify(payload) });
}
}
} catch (e) { /* network errors only */ } Prevention
- Keep an enum/union of provider slugs shared by client and server.
- Send the exact lowercase slug — comparison is case-sensitive after trim.
- Omit provider to accept the default "codex".
- Note opencode additionally requires a model containing "/" — validate both together.
When it happens
Trigger: POSTing to the capability issue-thread server with provider set to an unsupported string (e.g. "claude", "cursor", "Codex" with different case/whitespace is trimmed so case matters), a number, or a misspelled provider name.
Common situations: Typo like "claude_managed " with odd casing or "opencode-remote"; older clients sending provider names from a previous API revision; hand-written curl/test payloads using the display name instead of the slug; providers removed/renamed across versions.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid status '${String(rawStatus)}'. Must be one of: ${PLU
- "tool" is required and must be a string
- "runContext" is required and must be an object
- "runContext" must include agentId, runId, companyId, and pro
- "configJson" is required and must be an object
AI-assisted analysis of paperclipai/paperclip@5716fe907e (2026-09-02).
Data as JSON: /api/errors/94d51fe15adfade8.
Report an issue: GitHub.