musistudio/claude-code-router · error · Error
aspect_ratio must be one of ${constraints.aspectRatios.join(
Error message
aspect_ratio must be one of ${constraints.aspectRatios.join(", ")} for ${target.protocol}. What it means
Thrown when an aspect_ratio was supplied but is not in the protocol's aspectRatios allowlist. The message lists the accepted values.
Source
Thrown at packages/core/src/media/service.ts:173
if (!Number.isInteger(durationValue)) throw new Error("duration must be an integer number of seconds.");
if (constraints.durations && !constraints.durations.includes(durationValue)) {
throw new Error(`duration must be one of ${constraints.durations.join(", ")} seconds for ${target.protocol}.`);
}
if (constraints.durationMinimum !== undefined && constraints.durationMaximum !== undefined &&
(durationValue < constraints.durationMinimum || durationValue > constraints.durationMaximum)) {
throw new Error(`duration must be between ${constraints.durationMinimum} and ${constraints.durationMaximum} seconds for ${target.protocol}.`);
}
const resolution = optionalString(args.resolution) ?? constraints.defaultResolution;
if (!resolution) throw new Error(`resolution is required for ${target.protocol}.`);
if (!constraints.resolutions.includes(resolution)) {
throw new Error(`resolution must be one of ${constraints.resolutions.join(", ")} for ${target.protocol}.`);
}
const aspectRatio = optionalString(args.aspect_ratio);
if (constraints.requiredParameters.includes("aspect_ratio") && !aspectRatio) {
throw new Error(`aspect_ratio is required for ${target.protocol}.`);
}
if (aspectRatio && !constraints.aspectRatios.includes(aspectRatio)) {
throw new Error(`aspect_ratio must be one of ${constraints.aspectRatios.join(", ")} for ${target.protocol}.`);
}
const request: VideoGenerateRequest = {
aspectRatio,
duration: durationValue,
images: args.images === undefined && args.image === undefined ? [] : this.validateImages(args.images ?? args.image, 1, 7),
prompt: requiredPrompt(args.prompt),
resolution
};
const job = this.submit("video-generate", request, modelPlan, optionalString(args.idempotency_key));
return this.publicJob(job);
}
getJob(id: string): PublicMediaJob {
const job = this.jobStore.get(id);
if (!job) throw new Error(`Media job not found: ${id}`);
return this.publicJob(job);
}
View on GitHub (pinned to 99f24806c6)
Solutions
- Use an exact value from the error message's allowlist
- Build the UI selector from videoGenerationConstraints(protocol).aspectRatios
- If aspect ratio is optional, omit it rather than guessing an invalid value
Example fix
// before
media.videoStart({ ..., aspect_ratio: "landscape" }, modelInput);
// after
media.videoStart({ ..., aspect_ratio: "16:9" }, modelInput); Defensive patterns
Strategy: validation
Validate before calling
const c = videoGenerationConstraints(protocol);
if (args.aspect_ratio && !c.aspectRatios.includes(args.aspect_ratio)) {
args.aspect_ratio = c.aspectRatios[0]; // snap to first allowed
} Type guard
const isAllowedAspectRatio = (a: string, c: VideoConstraints): boolean => c.aspectRatios.includes(a);
Prevention
- Use the provider's exact ratio strings
- Omit aspect_ratio instead of guessing
When it happens
Trigger: Passing aspect_ratio: "4:3" to a protocol that only supports ["16:9","9:16"], or using alternate notations like "landscape" or "1.777".
Common situations: Provider-specific ratio vocabularies (16:9 vs widescreen vs 1792x1024); user free-text input; hardcoded values from a different provider integration.
Related errors
- duration must be one of ${constraints.durations.join(", ")}
- resolution must be one of ${constraints.resolutions.join(",
- aspect_ratio is required for ${target.protocol}.
- duration is required for ${target.protocol}.
- duration must be an integer number of seconds.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/7dfa5f2ec7a24604.
Report an issue: GitHub.