Troubleshooting

unipress surfaces actionable failures at install and compile time — each names a class and a cause. This file pairs each with what it usually means and how to fix it.

Every unipress compile error exits with code 1 (user-addressable). Unknown errors exit with code 2 — those are internal bugs; re-run with --verbose and open an issue.


Homebrew: Error: Refusing to load formula ... from untrusted tap uniweb/unipress

Recent Homebrew (6.x) won't load a formula from a third-party tap until you've trusted it once. This blocks both the first brew install uniweb/unipress/unipress and later brew upgrade unipress.

Trust the tap once, then re-run the command:

brew trust uniweb/unipress
brew upgrade unipress          # or: brew install uniweb/unipress/unipress

This is a Homebrew policy for third-party taps, not specific to unipress. The npm install (npm i -g @uniweb/unipress) and the prebuilt binaries on the releases page are unaffected.

ContentDirectoryError: content directory does not exist: <path>

The positional argument to unipress compile is wrong. Check your cd and the spelling. Paths are relative to the current working directory.

DocumentYmlError: no document.yml (or site.yml) found in <path>

unipress expects a top-level config file inside the content directory.

If the folder already holds markdown, you don't have to write one by hand — compile offers to generate it. Running interactively, it prompts:

$ unipress compile .
No document.yml here. Generate one (A4 article, pdf) from the 12 markdown files at the project root and compile? (Y/n)
Document title › My Document
created /path/to/document.yml

By default this produces a clean single-column article (A4, no chapters). Pass --yes to skip the prompt (handy in scripts or non-interactive shells):

unipress compile . --yes                     # generate + compile → A4 article PDF
unipress compile . --yes --foundation @unipress/data@0.1.1 --format docx

The generated document.yml pins a foundation, sets the format, lists the sections in reading order, and — when the markdown sits loose at the project root rather than under content/ — points the content directory at the root with paths: { pages: . }. It's an ordinary config file; edit it freely.

To write one by hand instead:

foundation: "@unipress/book@0.4.3"
format: pdf
paths:
  pages: .          # only needed when sections live at the root (no content/ folder)
book:
  kind: article     # single-column paper; omit for a chaptered book
  trim: a4          # or: letter
content: [introduction, main]

site.yml is accepted as a fallback if you're dogfooding an existing Uniweb site.

DocumentYmlError: <config> has no pages — nothing to compile

A config file exists, but the collector found no chapters. The usual cause is markdown living somewhere the document profile didn't scan — loose at the project root while the profile looks under content/. The error names the fix; for root-level files, add paths: { pages: . } to your document.yml.

DocumentYmlError: malformed YAML in document.yml at <file>:<line>:<col>

Fix the YAML. Common causes: unquoted strings containing :, unclosed brackets, inconsistent indentation, tabs mixed with spaces.

Note: @uniweb/build's content collector currently catches YAML errors internally, logs [content-collector] YAML parse error: ... as a warning, and proceeds with an empty config. You'll typically see a downstream error like "no format specified" or "no foundation specified" — the YAML warning in the log is the real cause. Fix the YAML first, then re-run.

DocumentYmlError: no format specified — pass --format <fmt> or set format: in document.yml

No format is declared in the CLI, unipress.config.js, or document.yml. Pick one:

unipress compile ./my-book --format pdf

Or add it to document.yml:

format: pdf

The error also lists unipress.config.js as an option when a config file is loaded.

FoundationResolutionError: no foundation specified

Set foundation: in document.yml, or pass --foundation <ref>. Four ref forms accepted:

# Registry ref (recommended) — resolved against UNIWEB_REGISTRY_URL
# or the default registry, https://uniweb.github.io/unipress.
foundation: "@unipress/book@0.1.0"

# Or a full URL.
foundation: "https://example.com/foundations/my-foundation/entry.js"

# Or a local filesystem path (relative to document.yml).
foundation: "./path/to/foundation"

# Or, inside a pnpm workspace, a bare package name (resolves through node_modules).
foundation: "@unipress/book"

FoundationResolutionError: cannot find foundation package '<name>' from <dir>

The package isn't installed anywhere Node can see from the content directory. Either:

  • Install it into node_modules/ locally: pnpm add <name> in the content directory (if the content dir is part of a workspace), or
  • Pass a local path: --foundation ../path/to/built-foundation.

Inside a pnpm workspace, foundations linked via pnpm-workspace.yaml globs resolve automatically.

FoundationResolutionError: expected built foundation at <path>/dist/entry.js

The foundation package isn't built. From the workspace root:

pnpm --filter <foundation-name> build

unipress consumes the built artifact (dist/entry.js), not the source.

CompileError: foundation does not expose compileDocument

The foundation doesn't depend on @uniweb/press, or was built with an older @uniweb/build that predates the compileDocument re-export.

Fix: add "@uniweb/press": "workspace:*" (or the appropriate version) to the foundation's dependencies, rebuild with a current @uniweb/build (57498ef or later), and re-install.

CompileError: foundation does not declare 'outputs.<format>'

The foundation doesn't support the format you asked for. The error lists the declared formats:

error: foundation does not declare 'outputs.docx' — cannot compile.
    available formats: typst, pdf, pagedjs, epub

Pick one of the listed formats, or pick a different foundation.

CompileError: foundation declares no outputs

The foundation is web-only — it has no outputs: map and can't be compiled as a document. Check the foundation's README to confirm it supports document output. Foundations that only drive websites can't be used with unipress.

TypstBinaryError: sha256 mismatch for typst <version>

The downloaded Typst archive doesn't match the pinned digest. Either the download was corrupted mid-transfer, or the pinned digest in src/typst/versions.js is stale.

Quick retry: delete the cache directory ($UNIPRESS_CACHE_DIR/typst/<version>) and re-run. If the mismatch persists, the pin is out of date — file an issue, or override with --typst-binary <path> pointing at a locally-installed Typst.

TypstBinaryError: typst exited with code 1

Typst rejected the foundation-generated source bundle. The error includes Typst's own stderr and a hint:

hint: pass --keep-temp to inspect the source bundle

With --keep-temp, the temp directory survives on failure. The path appears in the error:

typst exited with code 1 (temp dir kept at /var/folders/.../unipress-typst-XXXXXX)

Inspect main.typ, template.typ, meta.typ, content.typ in that directory. The root cause is usually:

  • The foundation's outputs[format].getOptions produced a partial meta object missing a field the foundation's template expects. Check the foundation's compile-options.js against its template.typ.
  • An image asset the bundle references is missing. Foundation-side: verify gatherCovers (or equivalent) found the image at the URL it computed.
  • A Typst syntax issue in the foundation's preamble or template. Check against the installed Typst version (typst --version).

OutputWriteError: failed to write output to <path>

The --out path can't be written. Most common causes: parent directory doesn't exist and unipress couldn't create it (permission denied), or the file exists and is locked by another process.

unipress creates missing parent directories automatically (like mkdir -p). If creation fails, check permissions on the destination.

ConfigValidationError: failed to load config file <path>

unipress.config.js threw during import. Common causes:

  • Syntax error — Node prints Unexpected end of input or similar as the cause.
  • Missing package — if the config import { defineUnipressConfig } from '@uniweb/unipress' and @uniweb/unipress isn't installed in that project, the import fails. Either pnpm add -D @uniweb/unipress in the content directory, or drop the import and use a plain export default { … }.

ConfigValidationError: config file <path> must default-export an object

The config file's default export is a string, number, array, or something else. It must be an object:

export default { format: 'pdf' }

Cover image (or other config asset) doesn't appear in the output

Not an error — a silent drop. The book compiles, but the front/back cover (or a banner/logo declared in config) is missing from the PDF/EPUB.

Config-declared asset paths — book.covers.front, book.covers.back, and the like — are resolved from the top-level config unipress reads for content collection: the default document.yml, or the file you pass to --document. They are not scanned from a unipress.config.js supplied via --config (that file layers build settings — out, format, typst — over the compile, after content is collected).

So if your covers live in document-book.yml, build it with --variant document-book — not --config document-book.yml. Confirm with --verbose: the Found N asset references line should count your covers (e.g. 2 more than the body images), and the source-bundle blob: size should grow by roughly the covers' byte size. Also confirm the files exist at the declared path relative to the content directory (e.g. assets/front.png).

Internal error (exit code 2)

Something unexpected threw — typically a library error or a code path unipress didn't wrap. Re-run with --verbose for a stack trace, then open an issue with the trace and a description of the content directory + foundation you're compiling.

unipress compile <dir> --verbose