affaan-m/ECC · error · Error

pandoc did not produce a nonempty regular DOCX artifact

Error message

pandoc did not produce a nonempty regular DOCX artifact

What it means

After a nominally successful pandoc run, build() verifies the artifact: it lstat's the DOCX path and requires a regular, non-empty file. If pandoc reported success but produced nothing usable (zero-byte file, directory, missing file), this error is thrown, the stale/partial docx is removed, and ENOENT is remapped to the clearer 'pandoc did not produce a DOCX artifact' message.

Solutions

  1. Check the output directory after failure — confirm whether any DOCX exists and its size (ls -la out/).
  2. Run pandoc manually with the same command and inspect its output/exit code for silent filter failures.
  3. Free up disk space if the volume is full; a full disk commonly yields empty artifacts.
  4. Rerun in an isolated output directory to rule out concurrent processes deleting the artifact.

Example fix

// before
$ pandoc md -o docx && echo ok   # exit 0, but docx is 0 bytes
// after
$ df -h .            # rule out disk-full
$ pandoc md -o docx --verbose   # surface silent filter failures
$ node build-agreement.js --spec spec.json --out out  # retry
Defensive patterns

Strategy: retry

Validate before calling

const fs = require('fs');
function verifyDocxArtifact(p) {
  const st = fs.lstatSync(p); // throws ENOENT if missing
  if (!st.isFile() || st.size === 0) throw new Error('DOCX artifact missing or empty');
}
verifyDocxArtifact(`${outDir}/${spec.file} MASTER.docx`);

Type guard

null

Try / catch

try {
  build(templatePath, specPath, outDir);
} catch (e) {
  if (e.message.includes('DOCX artifact')) {
    console.error('pandoc exited 0 but produced no usable DOCX; check filters and disk space');
  } else throw e;
}

Prevention

When it happens

Trigger: Pandoc exits 0 but writes to a different location, a zero-length .docx from a silently failing filter, or something (another process/cleanup hook) deleting the file between conversion and the lstat check.

Common situations: Flaky/silently failing pandoc filters or Lua filters; disk-full conditions yielding truncated/empty output; racing background jobs cleaning the output directory mid-build.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/bc3b75e3b3f625c9. Report an issue: GitHub.

Appendix: source

Thrown at skills/master-agreement-generator/scripts/build-agreement.js:188

  // beside a newly built Markdown draft, including explicit Markdown-only builds.
  fs.rmSync(docxPath, { force: true });
  const result = { markdown: mdPath, docx: null, docxSkipped: false, documentStatus: 'draft' };
  if (options.markdownOnly === true) {
    result.docxSkipped = true;
    return result;
  }
  const canConvert = options.pandoc === undefined ? pandocAvailable() : options.pandoc;
  if (!canConvert) {
    throw new Error('DOCX required: pandoc unavailable; use --markdown-only for an explicit Markdown-only draft');
  }
  try {
    const converted = spawnSync('pandoc', [mdPath, '-o', docxPath], CONVERTER_OPTIONS);
    if (converted.error || converted.status !== 0) {
      throw new Error('pandoc conversion failed; DOCX unavailable');
    }
    const artifact = fs.lstatSync(docxPath);
    if (!artifact.isFile() || artifact.size === 0) {
      throw new Error('pandoc did not produce a nonempty regular DOCX artifact');
    }
  } catch (error) {
    fs.rmSync(docxPath, { force: true });
    if (error.code === 'ENOENT') throw new Error('pandoc did not produce a DOCX artifact');
    throw error;
  }
  result.docx = docxPath;
  return result;
}

function main(argv) {
  const [templatePath, specPath, outDir, ...flags] = argv;
  if (!templatePath || !specPath || !outDir ||
      flags.some(flag => !['--require-docx', '--markdown-only'].includes(flag)) ||
      flags.length > 1) {
    console.error('usage: build-agreement.js <template.md> <spec.json> <out_dir> [--require-docx | --markdown-only]');
    return 2;
  }

View on GitHub (pinned to 8321021c54)