deepseek-ai/deepseek-harness · error · AttachmentError

INVALID_IMAGE

INVALID_IMAGE

Error message

Unsupported or malformed image data.

What it means

The raster inspector admits only PNG, JPEG, WebP, and GIF — the store's declared mediaTypes (MEDIA_TYPES in image.ts). imageMetadata throws INVALID_IMAGE when sharp's header parse reports any other format (TIFF, AVIF, HEIC, SVG, BMP, ...) or no recognizable format at all. This is admission policy, not a decode failure: sharp may support the format; this store does not.

Source

Thrown at packages/attachment/attachment-local/src/image.ts:66

  gif: 'image/gif',
}

function carriesRetainedMetadata(metadata: Awaited<ReturnType<Sharp['metadata']>>): boolean {
  return metadata.exif !== undefined
    || metadata.xmp !== undefined
    || metadata.iptc !== undefined
    || metadata.icc !== undefined
    || metadata.hasProfile
    || metadata.tifftagPhotoshop !== undefined
    || metadata.comments !== undefined
    || metadata.orientation !== undefined
}

async function imageMetadata(image: Sharp): Promise<DetectedImage> {
  const metadata = await image.metadata()
  const mediaType = MEDIA_TYPES[metadata.format as string]
  if (mediaType === undefined) {
    throw new AttachmentError('Unsupported or malformed image data.', 'INVALID_IMAGE')
  }
  // EXIF orientations 5-8 transpose the stored raster; report the perceived
  // axes so limits, source facts, and coordinate advice all share them.
  const transposed = metadata.orientation !== undefined && metadata.orientation >= 5
  return {
    mediaType,
    width: transposed ? metadata.height : metadata.width,
    height: transposed ? metadata.width : metadata.height,
    animated: (metadata.pages ?? 1) > 1,
    carriesMetadata: carriesRetainedMetadata(metadata),
    depth: metadata.depth,
    space: metadata.space,
    hasAlpha: metadata.hasAlpha,
  }
}

/**
 * Parse a supported raster's header and return its intrinsic metadata without

View on GitHub (pinned to b150a551b8)

Solutions

  1. Convert the image to a supported format before submitting: sharp(input).png().toBuffer() externally, or sips/ImageMagick on the client.
  2. Reject unsupported uploads client-side by checking the declared media type or magic bytes against the four supported formats.
  3. If the deployment genuinely needs another raster format, that requires changing MEDIA_TYPES in this package — there is no config field; request it upstream instead of catching and retrying.

Example fix

// before
const detected = await detectImage(heicBytes)

// after
const detected = await detectImage(await sharp(heicBytes).png().toBuffer())
Defensive patterns

Strategy: validation

Validate before calling

const isSupportedImage = (b: Uint8Array): boolean =>
  (b[0] === 0x89 && b[1] === 0x50)                                    // PNG
  || (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff)                 // JPEG
  || (b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46)                 // GIF
  || (b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57 && b[9] === 0x45) // RIFF....WEBP
if (!isSupportedImage(bytes)) throw new Error('convert to PNG/JPEG/WebP/GIF first')

Type guard

import { isImageAdmissionError } from '@deepseek-ai/dsh-attachment'
const isInvalidImage = (e: unknown): boolean =>
  isImageAdmissionError(e) && e.code === 'INVALID_IMAGE'

Try / catch

try {
  await store.saveImage(input)
} catch (error) {
  if (isImageAdmissionError(error) && error.code === 'INVALID_IMAGE') {
    // ask the sender to convert to PNG/JPEG/WebP/GIF; not retryable as-is
  }
  throw error
}

Prevention

When it happens

Trigger: Calling probeImage or detectImage (including the store's validateImage / saveImages admission path) with bytes whose container format falls outside {png, jpeg, webp, gif}: HEIC phone photos, TIFF scans, SVGs, AVIF/JXL files, or non-image bytes that still yield a parsable sharp format string.

Common situations: iPhone HEIC/HEIF screenshots and camera uploads; scanner or fax TIFF output; SVG assets sent as images; files renamed to .png without conversion; a producer pipeline switching its default encoder to AVIF.

Understand the failure class

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/e0e6b43fe8c6a57e. Report an issue: GitHub.