deepseek-ai/deepseek-harness · error · AttachmentError
ATTACHMENT_WRITE_FAILED
ATTACHMENT_WRITE_FAILED
Error message
Image normalization did not produce a single-frame 8-bit sRGB image with matching metadata.
What it means
After normalizeImage encodes a normalized variant, verifyNormalizedImage re-detects that output and asserts the normalization contract: same media type and dimensions as encoded, single-frame, no retained EXIF/ICC/metadata, 8-bit 'uchar' depth, 'srgb' colour space, and alpha compatible with the source. A mismatch means sharp/libvips produced output violating the invariant — an encoder or storage fault routed as ATTACHMENT_WRITE_FAILED, not a caller-input problem.
Source
Thrown at packages/attachment/attachment-local/src/normalization.ts:108
}
return true
}
/** Assert that a normalized output is an 8-bit sRGB/sRGBA single-frame image with matching facts. */
async function verifyNormalizedImage(
image: NormalizedImage,
expectedAlpha: boolean | undefined,
): Promise<NormalizedImage> {
const detected = await detectImage(image.data)
if (detected.mediaType !== image.mediaType
|| detected.width !== image.width
|| detected.height !== image.height
|| detected.animated
|| detected.carriesMetadata
|| detected.depth !== 'uchar'
|| detected.space !== 'srgb'
|| !encodedAlphaIsCompatible(expectedAlpha, detected)) {
throw new AttachmentError(
'Image normalization did not produce a single-frame 8-bit sRGB image with matching metadata.',
'ATTACHMENT_WRITE_FAILED',
)
}
return image
}
/** Build one fixed-size, oriented, metadata-free sRGB pipeline from submitted bytes. */
function preparedPipeline(data: Uint8Array, width: number, height: number): Sharp {
return sharp(data, { failOn: 'error', limitInputPixels: false })
.rotate()
.toColourspace('srgb')
.resize({ width, height, fit: 'inside', withoutEnlargement: true })
}
/** Dimensions after the long edge is capped without changing aspect ratio. */
function initialDimensions(detected: DetectedImage, maxDimension: number): { width: number; height: number } {
const scale = Math.min(1, maxDimension / Math.max(detected.width, detected.height))View on GitHub (pinned to b150a551b8)
Solutions
- Re-encode the source externally to a clean, metadata-free 8-bit sRGB image and resubmit.
- Align the sharp/libvips version with the one this harness pins and retry.
- If reproducible on the pinned stack, report it upstream with the source image — this check exists to catch encoder regressions.
Example fix
// before
const normalized = await normalizeImage(data, detected, policy)
// after: pre-clean problem sources so the encode path starts from 8-bit sRGB
const clean = await sharp(data).rotate().toColourspace('srgb').png().toBuffer()
const normalized = await normalizeImage(clean, await detectImage(clean), policy) Defensive patterns
Strategy: try-catch
Type guard
const isNormalizationFault = (e: unknown): boolean =>
e instanceof Error && 'code' in e && (e as { code?: string }).code === 'ATTACHMENT_WRITE_FAILED' Try / catch
try {
const normalized = await normalizeImage(data, detected, policy)
} catch (error) {
if (isNormalizationFault(error)) {
// encoder/storage fault: surface for re-upload or an upstream report; same-bytes retry is futile
}
throw error
} Prevention
- Pin the sharp version this package was built against; treat libvips upgrades as breaking changes.
- Pre-strip metadata and normalize bit depth and colour space at the ingestion edge for exotic sources.
- Route ATTACHMENT_WRITE_FAILED to operators rather than end users — it is not caller-correctable.
When it happens
Trigger: normalizeImage returning an encode whose re-detection diverges: an encoder release that embeds an ICC profile or orientation tag, WebP dimension rounding differing from the encode info, a colourspace reported other than srgb, multi-frame output, or alpha dropped outside the tolerated all-opaque WebP case.
Common situations: sharp/libvips version drift after a dependency update changes metadata emission; platform libvips builds differing across Linux, macOS, and CI; usually deterministic for the same input and stack, so retries of the same bytes fail identically.
Related errors
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/0ccb48d2153306d8.
Report an issue: GitHub.