{"record":{"id":"657a07b8494bd375","repo":"musistudio/claude-code-router","slug":"video-fallback-model-selector-uses-target-pro","errorCode":null,"errorMessage":"Video fallback model ${selector} uses ${target.protocol}, but primary model ${modelSelector} uses ${primaryTarget.protocol}. Configure video fallback models with the same media protocol.","messagePattern":"Video fallback model (.+?) uses (.+?), but primary model (.+?) uses (.+?)\\. Configure video fallback models with the same media protocol\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/media/service.ts","lineNumber":262,"sourceCode":"\n  private mediaModelPlan(operation: MediaOperation, modelInput: MediaModelInput, options: { dropIncompatibleVideoFallbacks?: boolean } = {}): MediaModelPlan {\n    const config = this.requireConfig();\n    const source = typeof modelInput === \"string\" ? { modelSelector: modelInput } : modelInput;\n    const modelSelector = normalizeMediaModelSelector(config, source.modelSelector, operation);\n    const primaryTarget = resolveProviderMediaTarget(config, modelSelector, operation);\n    const fallbackModelSelectors: string[] = [];\n    const retryCount = clampInteger(source.retryCount ?? 0, 0, ROUTER_FALLBACK_MAX_RETRY_COUNT);\n    for (const sourceSelector of source.fallbackModelSelectors ?? []) {\n      const selector = normalizeMediaModelSelector(config, sourceSelector, operation);\n      if (selector === modelSelector || fallbackModelSelectors.includes(selector)) {\n        continue;\n      }\n      const target = resolveProviderMediaTarget(config, selector, operation);\n      if (operation === \"video-generate\" && target.protocol !== primaryTarget.protocol) {\n        if (options.dropIncompatibleVideoFallbacks) {\n          continue;\n        }\n        throw new Error(\n          `Video fallback model ${selector} uses ${target.protocol}, but primary model ${modelSelector} uses ${primaryTarget.protocol}. ` +\n          \"Configure video fallback models with the same media protocol.\"\n        );\n      }\n      fallbackModelSelectors.push(selector);\n    }\n    return {\n      fallbackModelSelectors,\n      modelSelector,\n      retryCount\n    };\n  }\n\n  private videoToolBindingForRuntime(binding: MediaToolBinding): MediaToolBinding {\n    const config = this.requireConfig();\n    const modelSelector = normalizeMediaModelSelector(config, binding.modelSelector, \"video-generate\");\n    const primaryTarget = resolveProviderMediaTarget(config, modelSelector, \"video-generate\");\n    const fallbackModelSelectors: string[] = [];","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/media/service.ts#L244-L280","documentation":"When planning a video-generate request, MediaService verifies that every fallback model speaks the same media protocol (e.g. xai_video_generations vs openai_video_generations) as the primary model, because mid-request failover cannot switch protocols. A mismatch aborts planning unless explicitly permitted.","triggerScenarios":"Calling mediaModelPlan (or modelPlan) for video-generate where the primary video model resolves to one protocol and a fallback model resolves to another provider protocol.","commonSituations":"Mixing an xAI/Grok video primary with an OpenAI-compatible video fallback (or vice versa) in the model fallback chain configuration.","solutions":["Set the video fallback models to providers using the same media protocol as the primary","Remove the incompatible model from the video fallback list","Pass dropIncompatibleVideoFallbacks: true in plan options to silently skip mismatched fallbacks"],"exampleFix":"// before\n{ model: \"grok-video-primary\", fallbacks: [\"openai/sora\"] }\n// after\n{ model: \"grok-video-primary\", fallbacks: [\"xai/grok-video-2\"] }","handlingStrategy":"validation","validationCode":"const plan = service.mediaModelPlan(config, { operation: \"video-generate\", dropIncompatibleVideoFallbacks: true });","typeGuard":"null","tryCatchPattern":"try { service.mediaModelPlan(config, opts); } catch (e) { if (e instanceof Error && e.message.includes(\"same media protocol\")) {/* align fallbacks */} throw e; }","preventionTips":["Keep per-operation fallback lists","Group video fallbacks by provider protocol"],"tags":["media","video","configuration","fallback"],"backgroundTag":"incompatible-provider-configuration","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}