d2lang/d2 · error · Error

response.error.message

Error message

response.error.message

What it means

In the Node worker's handleMessage, the 'compile' case calls await d2.compile(JSON.stringify(data)) and, if the JSON envelope returned includes an `error` field, throws new Error(response.error.message). This surfaces a D2 compilation failure (invalid diagram syntax) as a worker 'error' response to the main thread.

Source

Thrown at d2js/js/src/worker.node.js:34

    switch (type) {
      case "init":
        try {
          if (isNode) {
            loadScript(data.wasmExecContent);
          }
          d2 = await initWasm(data.wasm);
          currentPort.postMessage({ type: "ready" });
        } catch (err) {
          currentPort.postMessage({ type: "error", error: err.message });
        }
        break;

      case "compile":
        try {
          const result = await d2.compile(JSON.stringify(data));
          const response = JSON.parse(result);
          if (response.error) throw new Error(response.error.message);
          currentPort.postMessage({ id, type: "result", data: response.data });
        } catch (err) {
          currentPort.postMessage({ id, type: "error", error: err.message });
        }
        break;

      case "render":
        try {
          const result = await d2.render(JSON.stringify(data));
          const response = JSON.parse(result);
          if (response.error) throw new Error(response.error.message);
          const decoded = new TextDecoder().decode(
            Uint8Array.from(atob(response.data), (c) => c.charCodeAt(0))
          );
          currentPort.postMessage({ id, type: "result", data: decoded });
        } catch (err) {
          currentPort.postMessage({ id, type: "error", error: err.message });
        }

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Read err.message in the main-thread 'error' response — it contains the D2 compiler's line/column diagnostics; fix the document.
  2. Validate the D2 syntax with the d2 CLI (d2 validate) before compiling in the worker.
  3. Confirm the request payload structure matches what d2.compile expects (JSON.stringify(data) contract).
  4. Check d2 WASM version compatibility with the syntax you are using; upgrade d2js if using newer language features.

Example fix

// before
worker.postMessage({ id, type: "compile", data: { d2: generated } });
// after
// fix the source indicated in err.message, e.g.:
//   err.message === "...: unclosed block" -> close the block in `generated`
const fixed = closeBlocks(generated);
worker.postMessage({ id, type: "compile", data: { d2: fixed } });
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate the D2 document before compiling
constbalancedBlocks = (doc) => {
  let n = 0;
  for (const ch of doc) if (ch === "{") n++; else if (ch === "}") n--;
  return n === 0;
};
if (typeof doc !== "string" || !doc.trim() || !balancedBlocks(doc)) {
  throw new TypeError("compile requires a non-empty, structurally valid D2 document");
}

Type guard

function isCompileRequest(data) {
  return data !== null && typeof data === "object" &&
    typeof data.d2 === "string" && data.d2.trim().length > 0;
}

Try / catch

worker.onmessage = (e) => {
  if (e.data.type === "error") {
    // e.data.error holds d2 compile diagnostics incl. line/col
    console.error("D2 compile failed:", e.data.error);
    return;
  }
  // e.data.data = compiled result
};

Prevention

When it happens

Trigger: Posting {type:'compile'} with a D2 document that fails compilation — syntax errors, unknown shape/icon keywords, invalid connections, or a payload not shaped as d2.compile expects.

Common situations: Generating D2 from templates and emitting invalid syntax; using keywords/newer syntax unsupported by the installed d2 WASM; passing an object where the compiled API expected JSON.stringify'd input fields.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/28ebecfce2598bb7. Report an issue: GitHub.