musistudio/claude-code-router · error · Error
images must contain between ${min} and ${max} local image pa
Error message
images must contain between ${min} and ${max} local image paths. What it means
validateImages enforces that the images argument is a string or array of non-empty strings whose count lies within [min, max] for the given media operation. Wrong types, empty/blank entries, or out-of-range counts throw this error before any filesystem access.
Source
Thrown at packages/core/src/media/service.ts:521
private startCleanup(): void {
if (this.cleanupTimer) clearInterval(this.cleanupTimer);
this.cleanup();
this.cleanupTimer = setInterval(() => this.cleanup(), 60 * 60 * 1000);
this.cleanupTimer.unref?.();
}
private cleanup(): void {
const now = Date.now();
for (const job of this.jobStore.list()) {
if (job.artifact && Date.parse(job.artifact.expiresAt) <= now) this.artifactStore.delete(job.artifact);
}
for (const job of this.jobStore.deleteOlderThan(now - jobRetentionDays * 24 * 60 * 60 * 1000)) this.artifactStore.delete(job.artifact);
}
private validateImages(value: unknown, min: number, max: number): string[] {
const raw = typeof value === "string" ? [value] : Array.isArray(value) ? value : [];
if (raw.length < min || raw.length > max || raw.some((item) => typeof item !== "string" || !item.trim())) {
throw new Error(`images must contain between ${min} and ${max} local image paths.`);
}
const roots = mediaInputRoots(this.requireRuntimeConfig().allowedInputRoots);
return raw.map((item) => {
const resolved = realpathSync(expandHome(String(item).trim()));
if (!roots.some((root) => isPathInside(resolved, root))) throw new Error(`Input image is outside allowed roots: ${resolved}`);
const stats = statSync(resolved);
if (!stats.isFile() || stats.size <= 0 || stats.size > maxInputBytes) throw new Error(`Input image must be a non-empty regular file no larger than ${maxInputBytes} bytes.`);
if (!detectMediaType(resolved).mimeType?.startsWith("image/")) throw new Error(`Unsupported input image format: ${resolved}`);
return resolved;
});
}
private finishCanceled(job: MediaJob, message: string): MediaJob {
const next = this.jobStore.update(job.id, {
error: { code: "canceled", message, retryable: false },
finishedAt: new Date().toISOString(),
status: "canceled"
});View on GitHub (pinned to 99f24806c6)
Solutions
- Check the operation's required image count and send within min..max
- Ensure every entry is a non-empty trimmed string path
- Validate the images field shape (string | string[]) before calling the tool
Example fix
// before
{ prompt: "...", images: [] }
// after
{ prompt: "...", images: ["/data/allowed/input.png"] } Defensive patterns
Strategy: validation
Validate before calling
const imgs = typeof images === "string" ? [images] : images;
if (!Array.isArray(imgs) || imgs.length < min || imgs.length > max || imgs.some(i => typeof i !== "string" || !i.trim())) throw new TypeError("bad images"); Type guard
const isValidImages = (v: unknown, min: number, max: number): v is string[] => (typeof v === "string" ? [v] : Array.isArray(v) ? v : []).length >= min && (typeof v === "string" ? [v] : Array.isArray(v) ? v : []).length <= max;
Try / catch
try { service.editImage(args); } catch (e) { if (e instanceof Error && e.message.startsWith("images must contain")) return badRequest(); throw e; } Prevention
- Validate tool args against the MCP input schema before dispatch
- Always send trimmed non-empty string paths
When it happens
Trigger: Passing images: null/number/object, an empty or blank string entry, fewer than min or more than max paths for the operation (e.g. an image-edit operation requiring at least one input image).
Common situations: Omitting required reference images for edit/variation endpoints, sending too many images for a single call, or forwarding unvalidated JSON tool arguments straight into the media tool.
Related errors
- The CCR artifact endpoint returned a non-media content type.
- The CCR media artifact exceeds the inline preview size limit
- Compressed CCR media artifacts are not accepted for inline p
- The CCR artifact response was empty.
- The CCR artifact content did not match its declared media ty
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/c0b0c64e9ef4cd9c.
Report an issue: GitHub.