{"record":{"id":"8f4a8857b051f812","repo":"KeygraphHQ/shannon","slug":"shannon-ai-openai-format-must-be-one-of-object","errorCode":null,"errorMessage":"SHANNON_AI_OPENAI_FORMAT must be one of: ${Object.keys(OPENAI_FORMATS).join(', ')}. Got \"${raw}\".","messagePattern":"SHANNON_AI_OPENAI_FORMAT must be one of: (.+?)\\. Got \"(.+?)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/worker/src/ai/models.ts","lineNumber":93,"sourceCode":"\n/** Format assumed when a gateway is configured but no format is named. */\nexport const DEFAULT_OPENAI_FORMAT: OpenAiFormat = 'chat-completions';\n\nfunction isOpenAiFormat(value: string): value is OpenAiFormat {\n  return value in OPENAI_FORMATS;\n}\n\n/**\n * Read SHANNON_AI_OPENAI_FORMAT. Unset returns undefined, which lets the caller\n * distinguish \"not configured\" from an explicit choice and reject the variable\n * where it has no effect.\n */\nexport function resolveOpenAiFormat(): OpenAiFormat | undefined {\n  const raw = process.env.SHANNON_AI_OPENAI_FORMAT?.trim();\n  if (!raw) return undefined;\n\n  if (!isOpenAiFormat(raw)) {\n    throw new Error(\n      `SHANNON_AI_OPENAI_FORMAT must be one of: ${Object.keys(OPENAI_FORMATS).join(', ')}. Got \"${raw}\".`,\n    );\n  }\n  return raw;\n}\n\nexport interface ModelSpec {\n  providerId: string;\n  modelId: string;\n}\n\n/**\n * Parse a `<provider>:<model-id>` spec. Splits on the first colon only, so colons\n * inside a model ID survive. The provider id is passed through as given — pi's\n * registry validates it later — so this throws only on a malformed spec.\n */\nexport function parseModelSpec(spec: string): ModelSpec {\n  const trimmed = spec.trim();","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/KeygraphHQ/shannon/blob/1ae0a142f8525410a688f0309fd003cc5b1d92de/apps/worker/src/ai/models.ts#L75-L111","documentation":"Rejects an invalid value for the SHANNON_AI_OPENAI_FORMAT environment variable. The variable selects which OpenAI wire format a gateway serves and accepts only the keys of OPENAI_FORMATS: 'chat-completions' or 'responses'. Any other value is thrown rather than silently ignored, so the wrong format never reaches a request.","triggerScenarios":"Set SHANNON_AI_OPENAI_FORMAT to a value that is not 'chat-completions' or 'responses', then invoke resolveOpenAiFormat() directly or via resolveGatewayFormat()/resolveModelSelection() (e.g. the preflight probe of `./shannon start`).","commonSituations":"Using the mapped pi API id instead of the key ('openai-completions'), underscores ('chat_completions'), camelCase ('chatCompletions'), or a stale value left over from an older Shannon version after the format names changed.","solutions":["Set SHANNON_AI_OPENAI_FORMAT to exactly 'chat-completions' or 'responses'.","If you do not need to override the default, unset the variable to fall back to 'chat-completions'.","Double-check shell quoting/export so no trailing whitespace or quotes are attached."],"exampleFix":"// before\nexport SHANNON_AI_OPENAI_FORMAT=openai-completions   # wrong: that is the pi API id, not the key\n\n// after\nexport SHANNON_AI_OPENAI_FORMAT=chat-completions","handlingStrategy":"validation","validationCode":"const VALID_FORMATS = ['chat-completions', 'responses'] as const;\nconst raw = process.env.SHANNON_AI_OPENAI_FORMAT?.trim();\nif (raw && !(VALID_FORMATS as readonly string[]).includes(raw)) {\n  console.error(`Invalid SHANNON_AI_OPENAI_FORMAT=\"${raw}\". Must be one of: ${VALID_FORMATS.join(', ')}`);\n  process.exit(1);\n}","typeGuard":"function isOpenAiFormat(value: string): value is 'chat-completions' | 'responses' {\n  return value === 'chat-completions' || value === 'responses';\n}","tryCatchPattern":null,"preventionTips":["Set SHANNON_AI_OPENAI_FORMAT only when routing OpenAI through a gateway.","Use the key name ('chat-completions'), never the mapped pi API id ('openai-completions').","Echo the variable before launching a scan to catch typos."],"tags":["config","environment","model-selection","openai","gateway"],"backgroundTag":null,"analyzedSha":"1ae0a142f8525410a688f0309fd003cc5b1d92de","analyzedAt":"2026-08-12T17:40:03.583Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}