linshenkx/prompt-optimizer · error · Error
Not a PNG file
Error message
Not a PNG file
What it means
Thrown by insertPngTextChunk when the input byte array fails the PNG signature check (isPng). The utility embeds a tEXt chunk into a PNG, so it requires a valid PNG file starting with the 8-byte PNG magic signature. Any non-PNG input (JPEG, WebP, corrupted bytes, or a data URL prefix that wasn't stripped) triggers this error.
Source
Thrown at packages/ui/src/utils/favorite-share-export.ts:1286
const crc32 = (bytes: Uint8Array): number => {
const table = getCrcTable()
let crc = 0xffffffff
for (const byte of bytes) {
crc = table[(crc ^ byte) & 0xff] ^ (crc >>> 8)
}
return (crc ^ 0xffffffff) >>> 0
}
const isPng = (bytes: Uint8Array): boolean =>
PNG_SIGNATURE.every((byte, index) => bytes[index] === byte)
export const insertPngTextChunk = (
pngBytes: Uint8Array,
keyword: string,
text: string,
): Uint8Array => {
if (!isPng(pngBytes)) throw new Error('Not a PNG file')
const encoder = new TextEncoder()
const type = encoder.encode('tEXt')
const data = encoder.encode(`${keyword}\u0000${text}`)
const chunk = createPngChunk(type, data)
return insertPngChunkAfterIhdr(pngBytes, chunk)
}
export const insertPngInternationalTextChunk = (
pngBytes: Uint8Array,
keyword: string,
text: string,
options: {
compressed?: boolean
languageTag?: string
translatedKeyword?: string
} = {},
): Uint8Array => {View on GitHub (pinned to 3e677b1d9f)
Solutions
- Verify the input is a PNG before calling: check the first 8 bytes equal [137,80,78,71,13,10,26,10]
- If the image may be another format, re-encode it via canvas: draw to a canvas and call toBlob(cb, 'image/png')
- Ensure you decoded base64/data URL to Uint8Array before passing (strip the data:image/...;base64, prefix)
- If the PNG came from an export pipeline, confirm no compression/transcoding step (e.g. optimizer) altered the file
Example fix
// before
const bytes = base64ToBytes(dataUrl) // dataUrl was 'data:image/jpeg;base64,...'
const out = insertPngTextChunk(bytes, 'key', 'value')
// after
const pngDataUrl = await reEncodeAsPng(dataUrl)
const bytes = base64ToBytes(pngDataUrl.split(',')[1])
if (!isPng(bytes)) throw new Error('Expected PNG')
const out = insertPngTextChunk(bytes, 'key', 'value') Defensive patterns
Strategy: type-guard
Validate before calling
const PNG_SIG = [137, 80, 78, 71, 13, 10, 26, 10] const isPngBytes = (b: Uint8Array) => b.length >= 8 && PNG_SIG.every((v, i) => b[i] === v) if (!isPngBytes(bytes)) bytes = await reEncodeAsPng(bytes)
Type guard
const isPngBytes = (b: Uint8Array): b is Uint8Array & { __png: true } =>
b.length >= 8 && [137,80,78,71,13,10,26,10].every((v,i) => b[i] === v) Try / catch
try {
const out = insertPngTextChunk(bytes, keyword, text)
} catch (e) {
if (e instanceof Error && e.message === 'Not a PNG file') {
// convert source to PNG and retry, or notify user
} else throw e
} Prevention
- Restrict file pickers to accept='image/png' or '.png'
- Re-encode user images to PNG via canvas before embedding metadata
- Always decode data URLs to raw bytes (strip prefix) before passing
When it happens
Trigger: Calling insertPngTextChunk(pngBytes, keyword, text) with bytes that are not a PNG: a JPEG/WebP/GIF export, a truncated or modified byte array, or a canvas export that was requested as image/jpeg instead of image/png.
Common situations: Exporting images with toDataURL('image/jpeg') then passing decoded bytes to a PNG-embedding API; passing a screenshot re-encoded by the OS clipboard; passing base64 string directly instead of decoded Uint8Array; file picked with accept='image/*' instead of 'image/png'.
Related errors
- CONTEXT_ERROR_CODES.STORAGE_ERROR
- CONTEXT_ERROR_CODES.IMPORT_FORMAT_ERROR
- DATA_ERROR_CODES.ELECTRON_API_UNAVAILABLE
- Data must be an object
- "data" property is missing or not an object
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/0aa3fe8e822afa51.
Report an issue: GitHub.