{"record":{"id":"0c62d1382e67ff4f","repo":"musistudio/claude-code-router","slug":"duration-must-be-an-integer-number-of-seconds","errorCode":null,"errorMessage":"duration must be an integer number of seconds.","messagePattern":"duration must be an integer number of seconds\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/media/service.ts","lineNumber":155,"sourceCode":"  }\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)) {\n      throw new Error(`aspect_ratio must be one of ${constraints.aspectRatios.join(\", \")} for ${target.protocol}.`);","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/media/service.ts#L137-L173","documentation":"Thrown by videoStart when the resolved duration is not an integer number of seconds. Providers require whole-second durations; fractional values like 4.5 fail this Number.isInteger check.","triggerScenarios":"Passing duration: 4.5, a computed float (e.g. from a division or unit conversion), or a numeric string parsed to a non-integer.","commonSituations":"Computing duration from milliseconds (ms/1000 producing 4.5); user input accepted as free-form decimals; defaulting to a fractional value from external config.","solutions":["Round to the nearest allowed integer: Math.round(duration)","Validate duration upstream with an integer-only input field (step=1)","Pick an integer from the protocol's allowed durations list"],"exampleFix":"// before\nmedia.videoStart({ prompt, duration: millis / 1000 }, modelInput);\n\n// after\nmedia.videoStart({ prompt, duration: Math.round(millis / 1000) }, modelInput);","handlingStrategy":"validation","validationCode":"if (typeof args.duration === \"number\" && !Number.isInteger(args.duration)) {\n  args.duration = Math.round(args.duration);\n}","typeGuard":"const isIntegerDuration = (d: unknown): d is number =>\n  typeof d === \"number\" && Number.isInteger(d) && d > 0;","tryCatchPattern":null,"preventionTips":["Use step=1 integer inputs for duration in UIs","Round any computed duration before calling videoStart"],"tags":["media","video","validation","integer"],"backgroundTag":"parameter-validation-failed","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}