{"record":{"id":"208c18698548f835","repo":"musistudio/claude-code-router","slug":"duration-is-required-for-target-protocol","errorCode":null,"errorMessage":"duration is required for ${target.protocol}.","messagePattern":"duration is required for (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/media/service.ts","lineNumber":154,"sourceCode":"    return this.submitAndWait(\"image-generate\", request, modelPlan, optionalString(args.idempotency_key));\n  }\n\n  async imageEdit(args: Record<string, unknown>, modelInput: MediaModelInput): Promise<PublicMediaJob> {\n    const request: ImageEditRequest = {\n      aspectRatio: optionalString(args.aspect_ratio),\n      images: this.validateImages(args.images ?? args.image, 1, 3),\n      prompt: requiredPrompt(args.prompt)\n    };\n    const modelPlan = this.mediaModelPlan(\"image-edit\", modelInput);\n    return this.submitAndWait(\"image-edit\", request, modelPlan, optionalString(args.idempotency_key));\n  }\n\n  videoStart(args: Record<string, unknown>, modelInput: MediaModelInput): PublicMediaJob {\n    const modelPlan = this.mediaModelPlan(\"video-generate\", modelInput);\n    const target = resolveProviderMediaTarget(this.requireConfig(), modelPlan.modelSelector, \"video-generate\");\n    const constraints = videoGenerationConstraints(target.protocol);\n    const durationValue = numberValue(args.duration) ?? constraints.defaultDuration;\n    if (durationValue === undefined) throw new Error(`duration is required for ${target.protocol}.`);\n    if (!Number.isInteger(durationValue)) throw new Error(\"duration must be an integer number of seconds.\");\n    if (constraints.durations && !constraints.durations.includes(durationValue)) {\n      throw new Error(`duration must be one of ${constraints.durations.join(\", \")} seconds for ${target.protocol}.`);\n    }\n    if (constraints.durationMinimum !== undefined && constraints.durationMaximum !== undefined &&\n      (durationValue < constraints.durationMinimum || durationValue > constraints.durationMaximum)) {\n      throw new Error(`duration must be between ${constraints.durationMinimum} and ${constraints.durationMaximum} seconds for ${target.protocol}.`);\n    }\n    const resolution = optionalString(args.resolution) ?? constraints.defaultResolution;\n    if (!resolution) throw new Error(`resolution is required for ${target.protocol}.`);\n    if (!constraints.resolutions.includes(resolution)) {\n      throw new Error(`resolution must be one of ${constraints.resolutions.join(\", \")} for ${target.protocol}.`);\n    }\n    const aspectRatio = optionalString(args.aspect_ratio);\n    if (constraints.requiredParameters.includes(\"aspect_ratio\") && !aspectRatio) {\n      throw new Error(`aspect_ratio is required for ${target.protocol}.`);\n    }\n    if (aspectRatio && !constraints.aspectRatios.includes(aspectRatio)) {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/media/service.ts#L136-L172","documentation":"Thrown by videoStart when no duration can be determined for a video generation protocol that has no default duration. It reads args.duration, falls back to the protocol's defaultDuration from videoGenerationConstraints, and throws if both are undefined.","triggerScenarios":"Starting a video generation with a protocol whose constraints define no defaultDuration and no duration argument supplied.","commonSituations":"Switching providers/protocols where one had a default and the new one doesn't; omitting duration because a previous protocol auto-filled it; args using a wrong key name so duration is never read.","solutions":["Pass an explicit integer duration in args: videoStart({ duration: 5, ... })","Check the protocol's supported durations via videoGenerationConstraints before calling","Verify the resolved target.protocol is the one you expect (model selector may map to a different provider)"],"exampleFix":"// before\nmedia.videoStart({ prompt: \"a cat\" }, modelInput);\n\n// after\nmedia.videoStart({ prompt: \"a cat\", duration: 5 }, modelInput);","handlingStrategy":"validation","validationCode":"const c = videoGenerationConstraints(protocol);\nconst duration = numberFrom(args.duration) ?? c.defaultDuration;\nif (duration === undefined) throw new Error(`duration required for ${protocol}`);","typeGuard":"const hasDuration = (a: Record<string, unknown>): boolean =>\n  typeof a.duration === \"number\" || a.duration === undefined;","tryCatchPattern":null,"preventionTips":["Always pass an explicit integer duration for video generation","Read protocol constraints to know when duration is mandatory"],"tags":["media","video","validation","duration"],"backgroundTag":"missing-required-parameter","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}