NousResearch/hermes-agent · error · Error
Could not read image
Error message
Could not read image
What it means
Thrown by copyImageFromUrl after resourceBufferFromUrl succeeded but nativeImage.createFromBuffer(buffer) produced an empty image (isEmpty()). Electron's nativeImage only decodes PNG/JPEG and a few formats; unsupported formats (e.g. AVIF, WebP on older Electron, SVG) or corrupt bytes yield an empty native image rather than a throw.
Source
Thrown at apps/desktop/electron/main.ts:4730
res.on('data', chunk => chunks.push(chunk))
res.on('end', () => {
resolve({
buffer: Buffer.concat(chunks),
mimeType: res.headers['content-type'] || 'application/octet-stream'
})
})
})
req.on('error', reject)
})
}
async function copyImageFromUrl(rawUrl) {
const { buffer } = (await resourceBufferFromUrl(rawUrl)) as any
const image = nativeImage.createFromBuffer(buffer)
if (image.isEmpty()) {
throw new Error('Could not read image')
}
clipboard.writeImage(image)
}
async function saveImageFromUrl(rawUrl) {
const { buffer, mimeType } = (await resourceBufferFromUrl(rawUrl)) as any
const fallbackName = filenameFromUrl(rawUrl, `image${extensionForMimeType(mimeType) || '.png'}`)
const result = await dialog.showSaveDialog(mainWindow, {
title: 'Save Image',
defaultPath: fallbackName
})
if (result.canceled || !result.filePath) {
return false
}
View on GitHub (pinned to c896c09c42)
Solutions
- Convert the image to PNG/JPEG before copying (e.g. decode in the renderer with createImageBitmap + canvas, then hand the PNG bytes to the clipboard path).
- If the source is SVG, rasterize it first — nativeImage cannot represent vector images.
- Verify the buffer bytes start with a known magic number (PNG \x89PNG, JPEG \xff\xd8) before calling.
Example fix
// before
const image = nativeImage.createFromBuffer(buffer)
if (image.isEmpty()) throw new Error('Could not read image')
// after — check magic bytes to distinguish 'unsupported codec' from 'not an image'
const isPng = buffer[0] === 0x89 && buffer[1] === 0x50
const isJpeg = buffer[0] === 0xff && buffer[1] === 0xd8
if (!isPng && !isJpeg) {
throw new Error('Could not read image (only PNG/JPEG are supported by nativeImage)')
}
const image = nativeImage.createFromBuffer(buffer) Defensive patterns
Strategy: try-catch
Validate before calling
function isDecodableImageBuffer(buf) {
if (!(buf && buf.length > 8)) return false
const isPng = buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47
const isJpeg = buf[0] === 0xff && buf[1] === 0xd8
return isPng || isJpeg
} Try / catch
try {
await copyImageFromUrl(url)
} catch (e) {
if (/Could not read image/.test(e.message)) {
await copyAsPngViaRenderer(url) // rasterize in renderer, then clipboard.writeImage
} else throw e
} Prevention
- Convert WebP/AVIF/SVG to PNG before clipboard writes
- Check image magic bytes before createFromBuffer
- Remember nativeImage decodes only a small format set
When it happens
Trigger: Copying an image whose bytes decoded fine but whose codec nativeImage can't parse; a buffer that is valid data but not an image at all; truncated download producing undecodable bytes.
Common situations: Modern web formats (WebP/AVIF) on Electron builds without codec support; SVG 'images'; partially downloaded files over flaky networks.
Related errors
- clipboard image is empty
- image too large (max ${mb} MB)
- Secure token storage is unavailable (no OS keyring service w
- Failed to encrypt the remote gateway token for secure storag
- An update is already in progress.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/c87e5ee3254f60d9.
Report an issue: GitHub.