JuliusBrussee/caveman · error · Error

[extract-atlas] missing base64 const

Error message

[extract-atlas] missing base64 const ${name}

What it means

`constB64` extracts base64 string constants (`const NAME = "...";`) from source text read by extract-atlas.mjs and decodes them to a Buffer. This error is thrown when the regex finds no match, meaning the expected base64 constant is missing or no longer a plain double-quoted string literal.

Solutions

  1. Restore the constant as a single-line double-quoted string: const NAME = "<base64>";
  2. Re-run the step that generates the embedded blob so the constant is regenerated in place
  3. If the data moved to a file, change extract-atlas.mjs to read the file instead of regexing source
  4. Check that the correct source text (not an empty or wrong file's contents) is passed to constB64

Example fix

// before
const ATLAS_PNG = await loadAtlas(); // dynamic, regex can't match
// after
const ATLAS_PNG = "iVBORw0KGgo..."; // plain base64 literal
Defensive patterns

Strategy: validation

Validate before calling

function b64ConstPresent(src, name) {
  return new RegExp(`const\\s+${name}\\s*=\\s*"([^"]+)"\\s*;`).test(src);
}
if (!b64ConstPresent(src, "ATLAS_PNG")) throw new Error("base64 blob constant missing");

Try / catch

try {
  runAtlasExtract();
} catch (e) {
  if (String(e.message).includes("missing base64 const")) {
    console.error("Regenerate the embedded base64 constant before extracting the atlas");
  } else throw e;
}

Prevention

When it happens

Trigger: Source no longer contains `const ${name} = "<base64>";` — the constant was renamed, moved to another file, changed to a template literal/backticks, imported instead of declared, or split across lines.

Common situations: A formatter or minifier rewrote the string literal; the asset blob was moved into a separate .json/.bin file during a refactor; the constant was made `export const` with extra spacing that still matches but the value was emptied and replaced with dynamic generation.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/1cb3b7e5940a5bfb. Report an issue: GitHub.

Appendix: source

Thrown at engine/pixel/internal/atlasgen/extract-atlas.mjs:37

const repoRoot = resolve(new URL('../../../../..', import.meta.url).pathname);
const outDir = join(repoRoot, 'public/engine/pixel/assets');
mkdirSync(outDir, { recursive: true });

function readSource(rel) {
  return readFileSync(join(pxpipeRoot, rel), 'utf8');
}

function constNumber(src, name) {
  const re = new RegExp(`export\\s+const\\s+${name}\\s*=\\s*(\\d+)\\s*;`);
  const m = src.match(re);
  if (!m) throw new Error(`[extract-atlas] missing numeric const ${name}`);
  return Number(m[1]);
}

function constB64(src, name) {
  const re = new RegExp(`const\\s+${name}\\s*=\\s*"([^"]+)"\\s*;`);
  const m = src.match(re);
  if (!m) throw new Error(`[extract-atlas] missing base64 const ${name}`);
  return Buffer.from(m[1], 'base64');
}

function assertHeader(src, expected) {
  for (const [name, want] of Object.entries(expected)) {
    const got = constNumber(src, name);
    if (got !== want) {
      throw new Error(`[extract-atlas] ${name}=${got}, want ${want}`);
    }
  }
}

function writeBlob(name, bytes) {
  const out = join(outDir, name);
  writeFileSync(out, gzipSync(bytes, { level: 9 }));
  console.log(`${basename(out)} raw=${bytes.length} gzip=${readFileSync(out).length}`);
}

View on GitHub (pinned to 3ee70a1026)