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

  1. Confirm the file was exported from Figma via File > Save local copy (.fig) — not a PNG/SVG/PDF export.
  2. Re-export the .fig file from Figma and re-import.
  3. If the file is a Jam board, ensure it was saved as .jam from Figma Jam.
  4. 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

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


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/6337d3b0127f542b. Report an issue: GitHub.