{"record":{"id":"bda9bd14ddb9a0f5","repo":"musistudio/claude-code-router","slug":"unsupported-input-image-format-resolved","errorCode":null,"errorMessage":"Unsupported input image format: ${resolved}","messagePattern":"Unsupported input image format: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/media/service.ts","lineNumber":529,"sourceCode":"    const now = Date.now();\n    for (const job of this.jobStore.list()) {\n      if (job.artifact && Date.parse(job.artifact.expiresAt) <= now) this.artifactStore.delete(job.artifact);\n    }\n    for (const job of this.jobStore.deleteOlderThan(now - jobRetentionDays * 24 * 60 * 60 * 1000)) this.artifactStore.delete(job.artifact);\n  }\n\n  private validateImages(value: unknown, min: number, max: number): string[] {\n    const raw = typeof value === \"string\" ? [value] : Array.isArray(value) ? value : [];\n    if (raw.length < min || raw.length > max || raw.some((item) => typeof item !== \"string\" || !item.trim())) {\n      throw new Error(`images must contain between ${min} and ${max} local image paths.`);\n    }\n    const roots = mediaInputRoots(this.requireRuntimeConfig().allowedInputRoots);\n    return raw.map((item) => {\n      const resolved = realpathSync(expandHome(String(item).trim()));\n      if (!roots.some((root) => isPathInside(resolved, root))) throw new Error(`Input image is outside allowed roots: ${resolved}`);\n      const stats = statSync(resolved);\n      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.`);\n      if (!detectMediaType(resolved).mimeType?.startsWith(\"image/\")) throw new Error(`Unsupported input image format: ${resolved}`);\n      return resolved;\n    });\n  }\n\n  private finishCanceled(job: MediaJob, message: string): MediaJob {\n    const next = this.jobStore.update(job.id, {\n      error: { code: \"canceled\", message, retryable: false },\n      finishedAt: new Date().toISOString(),\n      status: \"canceled\"\n    });\n    this.completions.get(job.id)?.resolve(next);\n    this.completions.delete(job.id);\n    return next;\n  }\n\n  private publicJob(job: MediaJob): PublicMediaJob {\n    const { artifact, idempotencyKeyHash: _idempotencyKeyHash, ...rest } = job;\n    return {","sourceCodeStart":511,"sourceCodeEnd":547,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/media/service.ts#L511-L547","documentation":"The service sniffs the file's magic bytes via detectMediaType and requires the detected MIME type to start with image/. Renamed files whose actual content is not an image (PDFs, videos, text) are rejected.","triggerScenarios":"Passing a file whose detected MIME is not image/* — e.g. a .png extension on a PDF, a video poster pulled as .mp4, or arbitrary binary data.","commonSituations":"User-uploaded files trusted by extension, mislabeled downloads, or attempting to feed documents into image editing models.","solutions":["Convert the actual content to a supported image format (PNG/JPEG/WebP)","Verify the source produces real image bytes before saving","Check the file with `file` or a magic-byte sniff on the producer side"],"exampleFix":"// before\nimages: [\"/data/report.png\"] // actually a PDF\n// after\nimages: [\"/data/report-page1.png\"] // converted with pdftoppm","handlingStrategy":"validation","validationCode":"const { mimeType } = detectMediaType(p); if (!mimeType?.startsWith(\"image/\")) throw new TypeError(`not an image: ${p}`);","typeGuard":"const isImageFile = (p: string): boolean => (detectMediaType(p).mimeType ?? \"\").startsWith(\"image/\");","tryCatchPattern":"try { await call(); } catch (e) { if (e instanceof Error && e.message.includes(\"Unsupported input image format\")) return convertFile(); throw e; }","preventionTips":["Sniff magic bytes on ingest","Never trust file extensions from users"],"tags":["media","mime-type","validation"],"backgroundTag":"unsupported-media-format","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}