13 Troubleshooting
How to read a diagnostic, and fixes for the common failures: no kernel, a hanging cell, stale outputs, a port in use.
Reference: Cheat sheet · CLI · Configuration · Cell options · Troubleshooting · Accessibility · Licensing
The preview shows most problems as a small diagnostics note in the corner (non-fatal) or a dismissible error overlay (a failed render). Here are the common ones.
13.1 Reading a diagnostic
Every diagnostic names its file, its line, its severity and, where there is a mechanical fix, the fix itself, inline:
post.tmd:3: warning: unknown front-matter key `titel` (did you mean `title`?)
post.tmd:18: error: broken cross-reference: @fig-los (did you mean `@fig-loss`?)
A near-miss gets a did-you-mean, which your editor offers as a quick fix over
taliesin lsp. A name with no near neighbour gets none. Taliesin suggests only names
from its own vocabulary and never another tool’s, so a key it has never had is reported
as unknown and left for you to look up.
13.2 Code cells show as source / “kernel unavailable”
Run taliesin doctor first: it names which
Python was resolved, which of the five sources chose it, and whether ipykernel imports.
The usual answer is that there is no Jupyter kernel. Create a virtual environment in the
project directory and install ipykernel into it:
&&
Taliesin finds a .venv in the project directory, or in a parent directory up to the
repository root, with no configuration. To use a Python somewhere else, set
TALIESIN_PYTHON to it. A plain pip install ipykernel into the system Python is refused
on current Debian, Ubuntu and Homebrew Pythons (externally-managed-environment, PEP 668).
The diagnostics note usually quotes the kernel’s own error (e.g. “No module
named ipykernel”), so fix that and save: the server respawns the kernel and
re-runs automatically, no restart needed. That includes a .venv created while the
preview runs and a python: changed in _site.yml. TALIESIN_PYTHON is read from the
environment the preview was started in, so a change to it needs a restart.
13.3 A cell hangs / runs forever
A cell is capped on silence, not on how long it runs. A cell that produces no
output for TALIESIN_CELL_SILENCE seconds (default 600) is interrupted
(SIGINT → KeyboardInterrupt); the warm kernel and prior cells survive. A long job
that prints progress as it goes resets that budget on every line, so it is never
interrupted however long it takes.
A long cell therefore needs no configuration if it prints something occasionally.
If a cell has to stay silent for longer than ten minutes, raise
TALIESIN_CELL_SILENCE or set it to 0.
To bound a cell’s total runtime regardless of output, set the optional
TALIESIN_CELL_TIMEOUT (wall-clock seconds, off by default). The dev menu’s
Restart kernel drops and respawns the kernel if it’s wedged.
A cell can also ignore the interrupt, by installing its own SIGINT handler or by sitting inside a C extension that never checks for signals. Five seconds after the interrupt Taliesin then stops the kernel, and the page says “cell ignored the interrupt, so the kernel was stopped; the cells after it did not run”. The next run starts a fresh kernel and re-runs from the top.
13.4 A cell ran, but I think the kernel crashed
If a kernel process dies mid-session (a segfault in a native library, an out-of-memory kill), Taliesin recovers without hanging. The cell that was running when the kernel died shows “KernelDied: kernel process exited mid-cell”, and the console names it as the cell that crashed the kernel; each cell after it shows “kernel exited before this cell ran; it runs again next time”. The next run notices the dead process, drops it, respawns a fresh kernel, and re-runs every cell from the top (the new kernel holds no state, so the warm prefix is gone). You don’t have to touch Restart kernel for this.
A failed start (a missing or misconfigured interpreter, not a mid-run crash) is
different: Taliesin backs off for about 20 seconds before retrying, so a broken
TALIESIN_PYTHON doesn’t re-hang every save. During the
backoff the cells render as source with the “kernel unavailable” diagnostic. Fix
the interpreter and the next save within a few tries recovers on its own; or hit
Restart kernel to clear the backoff and try immediately.
13.5 Outputs look stale, or I want to force a clean re-run
Cell outputs are cached in _freeze/ (gitignored), keyed by the cell’s code, every
upstream cell’s code and the interpreter. An edit to your code always moves the key, and
errors, #| cache: false cells and re-runs inside a warm kernel are never written, so an
edit to code cannot bring back an old output. What can go stale is what the key does not
see: a data file, an environment variable, a URL, the clock, a library upgraded in place.
Mark a cell that reads one #| cache: false. The preview does not watch data files, so
after editing data.csv save the .tmd (or use Restart kernel) to re-run it. If you
suspect a stale output anyway:
The dev menu’s Restart kernel forces the next run to ignore disk-cache hits and re-execute every cell against a fresh kernel (then re-persist), so it doubles as a “re-run everything from scratch” button.
TALIESIN_NO_CACHEignores the cache entirely and never writes it, so every run re-executes. Use it to compare timings, or to confirm a result reproduces from cold rather than from a replayed output:TALIESIN_NO_CACHE=1
13.6 Diagrams / {js} cells don’t render
Both run offline: Mermaid is vendored and {js} cells have d3 + Plot bundled, so a
missing network is not the cause. A {js} cell that import()s a relative helper module
does need http(s): the browser blocks module imports on file://, so use preview or
a served build.
13.7 “Port already in use”
preview automatically tries the next few ports and logs the substitution. Pass
an explicit port if you want a specific one: taliesin preview file.tmd 5000.
13.8 A broken {{< include >}}
A missing include is left on the page as literal text, plus a diagnostics note, so it never fails silently.
13.9 Edits aren’t picked up
A save rebuilds the open pages that read the file: a page’s source, an
{{< include >}}d file, a .bib, an image a page shows, a file a page links to. The
watcher covers the project’s folder and skips generated and .-prefixed folders
(_site, _book, _freeze, node_modules, .git, .venv). A stylesheet, a script or
a data file the page loads in the browser is not read by the render: reload the tab to see
a change to it.
13.10 The VS Code companion preview won’t connect
The companion spawns a plain taliesin preview <target> <port> and points its webview
at http://127.0.0.1:<port>/. <target> is the project root when the document
sits under a _site.yml (the webview then opens that page’s URL) and the file itself
otherwise. The preview binds loopback only, so no firewall needs opening.
If the panel stays blank:
- Make sure
taliesinis on the path the extension uses. It runs whatever thetaliesin.pathsetting points at (defaulttaliesin); set it to an absolute path if yourPATHdoesn’t have one. - The extension waits up to a few seconds for the server to answer on its port. If
you see “taliesin preview did not answer”, the binary failed to start: run the
same
taliesin preview <target>in a terminal to read the real error. - The preview is reachable only from this machine. A request whose
Hostheader names anything but a loopback name is refused (the DNS-rebinding guard), so a proxy or tunnel in front of it will get a 403.
13.11 A large site previews or builds slowly
A first cold build of a site with many executed cells has to run them once; after
that, their outputs come from _freeze/. Things that keep it fast:
Let the freeze cache warm up. The first run populates
_freeze/<page>.json; every laterbuild/previewof an unchanged page replays its outputs from disk and never boots a kernel. Don’t delete_freeze/between builds (it’s safe to commit if you want CI to skip execution), and don’t setTALIESIN_NO_CACHE, which turns the cache off.Use
--no-execfor a structure-only pass. When you’re iterating on layout, navigation, or prose and don’t need fresh cell outputs, render the code cells as source and skip the kernel entirely:The pages render in full (chrome, links, math) at a fraction of the cost, which also suits a quick look at a big site’s shape. Every code cell shows as source, including one whose output is already in
_freeze/: cached outputs are not shown.