nexu-io/open-design · error · Error
FIGMA_IMPORT_FAILED
FIGMA_IMPORT_FAILED
Error message
unexpected prelude "${prelude}" What it means
Plain Error thrown by decodeCanvas when the first 8 ASCII bytes of the .fig/.jam file do not match the magic prelude 'fig-kiwi' (FIG_MAGIC, a Figma design file) or 'fig-jam.' (JAM_MAGIC, a Figma Jam board). This is the file-format sentinel check at the entry of the binary container parser; anything that is not one of these two known Figma container formats is rejected before any chunk parsing.
Source
Thrown at apps/daemon/src/figma/fig-decode.ts:150
function hasFigPrelude(bytes: Uint8Array): boolean {
if (bytes.length < 8) return false;
const prelude = asciiAt(bytes, 0, 8);
return prelude === FIG_MAGIC || prelude === JAM_MAGIC;
}
interface CompiledFigSchema {
decodeMessage(bytes: Uint8Array): FigMessage;
}
interface FigMessage {
nodeChanges?: FigNodeChange[];
blobs?: Array<{ bytes?: Uint8Array }>;
}
function decodeCanvas(bytes: Uint8Array): FigMessage {
const prelude = asciiAt(bytes, 0, 8);
if (prelude !== FIG_MAGIC && prelude !== JAM_MAGIC) {
throw new Error(`unexpected prelude "${prelude}"`);
}
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
// bytes 8..11: u32 version (unused). Chunks begin at offset 12.
let offset = 12;
const chunks: Uint8Array[] = [];
while (offset + 4 <= bytes.length && chunks.length < 2) {
const len = view.getUint32(offset, true);
offset += 4;
if (len === 0 || offset + len > bytes.length) break;
chunks.push(bytes.subarray(offset, offset + len));
offset += len;
}
const schemaChunk = chunks[0];
const messageChunk = chunks[1];
if (!schemaChunk || !messageChunk) {
throw new Error('expected schema + message chunks');
}
const schemaBytes = decompressChunk(schemaChunk);View on GitHub (pinned to 5be4028344)
Solutions
- Confirm the file was exported from Figma via File > Save local copy (.fig) — not a PNG/SVG/PDF export.
- Re-export the .fig file from Figma and re-import.
- If the file is a Jam board, ensure it was saved as .jam from Figma Jam.
- If a genuinely new Figma format (new magic), the importer needs an additional prelude case — file a bug rather than catching the error.
Defensive patterns
Strategy: validation
Validate before calling
const FIG_MAGIC = 'fig-kiwi';
const JAM_MAGIC = 'fig-jam.';
function isFigContainer(bytes: Uint8Array): boolean {
if (bytes.length < 8) return false;
const prelude = Array.from(bytes.slice(0, 8), (b) => String.fromCharCode(b)).join('');
return prelude === FIG_MAGIC || prelude === JAM_MAGIC;
}
// before importing
if (!isFigContainer(fileBytes)) { reject('Not a valid .fig/.jam container'); } Try / catch
try {
await importFigma(fileBytes);
} catch (err) {
if (err instanceof Error && /unexpected prelude/.test(err.message)) {
return respond(415, { error: 'Not a Figma .fig/.jam file. Use File > Save local copy in Figma.' });
}
throw err;
} Prevention
- Export .fig via Figma File > Save local copy, not PNG/SVG/PDF export.
- Do not rename PNG/SVG files to .fig.
- Pre-check the 8-byte magic before invoking the importer.
When it happens
Trigger: Passing a non-Figma file to the Figma importer: a PNG/SVG export from Figma (which are not .fig containers), a .fig file from an older/newer Figma format that changed the prelude, a corrupted/truncated file shorter than 8 bytes, or any unrelated binary masquerading with a .fig extension.
Common situations: User downloads a PNG from Figma and renames it .fig; user selects the wrong file in the import dialog; partial download where the first bytes are missing; a third-party tool producing files with a .fig extension that are not Figma containers; very new Figma format that introduced a third magic string not yet handled here.
Related errors
- ${task.folder}: spritesheet is not webp/png/gif
- zip entry size mismatch: ${relPath}
- zip contains no files
- zip does not contain an HTML file
- invalid zip central directory
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/6337d3b0127f542b.
Report an issue: GitHub.