{"record":{"id":"94d51fe15adfade8","repo":"paperclipai/paperclip","slug":"invalid-provider","errorCode":"invalid_provider","errorMessage":"Provider must be codex, opencode, claude_managed, aws_agentcore, or acpx.","messagePattern":"Provider must be codex, opencode, claude_managed, aws_agentcore, or acpx\\.","errorType":"http","errorClass":"RouteError","httpStatus":400,"severity":"error","filePath":"packages/paperclip-runner/scripts/capability-issue-thread-server.mjs","lineNumber":212,"sourceCode":"        startedAt: null,\n        completedAt: null,\n      },\n    ],\n  });\n}\n\nclass RouteError extends Error {\n  constructor(status, code, message) {\n    super(message);\n    this.status = status;\n    this.code = code;\n  }\n}\n\nfunction harnessConfiguration(source, fallbackModel) {\n  const provider = source.provider === undefined ? \"codex\" : String(source.provider).trim();\n  if (provider !== \"codex\" && provider !== \"opencode\" && provider !== \"claude_managed\" && provider !== \"aws_agentcore\" && provider !== \"acpx\") {\n    throw new RouteError(400, \"invalid_provider\", \"Provider must be codex, opencode, claude_managed, aws_agentcore, or acpx.\");\n  }\n  const rawModel = source.model === undefined ? fallbackModel : source.model;\n  const model = rawModel === undefined || rawModel === null ? \"\" : String(rawModel).trim();\n  if (model.length > 256) throw new RouteError(400, \"invalid_model\", \"Model is too long.\");\n  if (provider === \"opencode\" && (!model || !model.includes(\"/\"))) {\n    throw new RouteError(400, \"invalid_model\", \"OpenCode requires a provider/model value.\");\n  }\n  if (provider === \"claude_managed\" && model !== \"claude-sonnet-5\") {\n    throw new RouteError(400, \"invalid_model\", \"Claude Managed requires exact model claude-sonnet-5.\");\n  }\n  if (provider === \"aws_agentcore\" && model !== \"global.anthropic.claude-sonnet-4-6\") {\n    throw new RouteError(400, \"invalid_model\", \"AWS AgentCore requires exact model global.anthropic.claude-sonnet-4-6.\");\n  }\n  const acpxAgent = source.acpxAgent === undefined ? \"codex\" : String(source.acpxAgent).trim();\n  if (provider === \"acpx\") {\n    if (!(acpxAgent in ACPX_QUALIFIED_MODELS)) {\n      throw new RouteError(400, \"invalid_acpx_agent\", \"ACPX agent must be claude or codex.\");\n    }","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/paperclipai/paperclip/blob/5716fe907e596ce73501408fc6efdb19fb61edf2/packages/paperclip-runner/scripts/capability-issue-thread-server.mjs#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{ \"provider\": \"Claude-Managed\", \"model\": \"claude-sonnet-4-5\" }\n// after\n{ \"provider\": \"claude_managed\", \"model\": \"claude-sonnet-4-5\" }","handlingStrategy":"validation","validationCode":"const PROVIDERS = new Set([\"codex\", \"opencode\", \"claude_managed\", \"aws_agentcore\", \"acpx\"]);\nfunction assertValidProvider(p) {\n  const v = p === undefined ? \"codex\" : String(p).trim();\n  if (!PROVIDERS.has(v)) throw new Error(`provider must be one of ${[...PROVIDERS].join(\", \")}`);\n  return v;\n}\nassertValidProvider(requestBody.provider);","typeGuard":"function isHarnessProvider(p) {\n  return p === undefined || [\"codex\", \"opencode\", \"claude_managed\", \"aws_agentcore\", \"acpx\"].includes(p);\n}","tryCatchPattern":"try {\n  const res = await fetch(url, { method: \"POST\", body: JSON.stringify(payload) });\n  if (res.status === 400) {\n    const body = await res.json();\n    if (body.code === \"invalid_provider\") {\n      // correct the provider client-side and retry once\n      payload.provider = \"codex\";\n      return fetch(url, { method: \"POST\", body: JSON.stringify(payload) });\n    }\n  }\n} catch (e) { /* network errors only */ }","preventionTips":["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."],"tags":["validation","http-400","provider","enum","api"],"backgroundTag":"invalid-enum-value","analyzedSha":"5716fe907e596ce73501408fc6efdb19fb61edf2","analyzedAt":"2026-09-02T18:44:00.616Z","contentChangedAt":"2026-09-02T18:44:00.616Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}