{"record":{"id":"4d9fbfe606537da5","repo":"musistudio/claude-code-router","slug":"a-media-model-must-be-selected","errorCode":null,"errorMessage":"A media model must be selected.","messagePattern":"A media model must be selected\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/media/service.ts","lineNumber":699,"sourceCode":"  ].map(canonicalInputRoot);\n  return [...new Set(roots)];\n}\n\nfunction canonicalInputRoot(value: string): string {\n  const resolved = path.resolve(expandHome(value));\n  return existsSync(resolved) ? realpathSync(resolved) : resolved;\n}\n\nfunction isSafeImplicitWorkingDirectory(workingDirectory: string, homeDirectory: string): boolean {\n  const resolvedWorkingDirectory = path.resolve(workingDirectory);\n  const resolvedHomeDirectory = path.resolve(homeDirectory);\n  return resolvedWorkingDirectory !== path.parse(resolvedWorkingDirectory).root &&\n    !isPathInside(resolvedHomeDirectory, resolvedWorkingDirectory);\n}\n\nfunction requiredModelSelector(value: string): string {\n  const selector = value?.trim();\n  if (!selector) throw new Error(\"A media model must be selected.\");\n  return selector;\n}\n\nfunction isProviderApiJob(job: MediaJob): boolean {\n  const backend = (job as unknown as { backend?: string }).backend;\n  return backend === \"gateway-media-api\" || backend === \"provider-api\" || backend === \"xai-api\";\n}\n\nfunction jobModelSelector(job: MediaJob): string;\nfunction jobModelSelector(job: MediaJob, required: false): string | undefined;\nfunction jobModelSelector(job: MediaJob, required = true): string | undefined {\n  const selector = optionalString((job as Partial<MediaJob>).modelSelector);\n  if (selector) return selector;\n  if (required) throw new Error(\"This media job has no media API model binding and cannot be resumed.\");\n  return undefined;\n}\n\nexport function resolveProviderMediaTarget(config: AppConfig, selector: string, operation?: MediaOperation): GatewayMediaTarget {","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/media/service.ts#L681-L717","documentation":"requiredModelSelector rejects an empty/whitespace model selector. Every media API path needs a concrete model choice; if none is configured or passed, this throws.","triggerScenarios":"Passing model: \"\" or omitting the model argument when no default media model is configured in the app config.","commonSituations":"Fresh install without a default media model, config migration wiped the setting, or the caller relies on a fallback that no longer exists.","solutions":["Pass an explicit non-empty model selector in the tool call","Configure a default media model in app configuration","Check for empty-string model values coming from env/config overrides"],"exampleFix":"// before\n{ prompt: \"...\", model: \"\" }\n// after\n{ prompt: \"...\", model: \"openai/gpt-image-1\" }","handlingStrategy":"validation","validationCode":"if (!model?.trim()) model = configuredDefaultMediaModel;\nif (!model?.trim()) throw new Error(\"no model selected\");","typeGuard":"const hasModelSelector = (m: unknown): m is string => typeof m === \"string\" && m.trim().length > 0;","tryCatchPattern":"try { await call(); } catch (e) { if (e instanceof Error && e.message === \"A media model must be selected.\") return configError(); throw e; }","preventionTips":["Configure a default media model","Fail fast at startup if no model is set"],"tags":["media","configuration","model-selection"],"backgroundTag":"missing-required-config","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}