Troubleshooting
Symptom-first fixes for the failures that actually come up running lakefront.
Node can’t run it
Install Bun 1.2 or later. lakefront ships TypeScript source rather than a
compiled build ("engines": { "bun": ">=1.2" } in its package.json).
Every deployment target, including Docker images, must include Bun.
open fails with LakeUnavailable
Check the postgres connection shape first. This is the error surfaced when
the engine’s ATTACH IF NOT EXISTS 'ducklake:<pgDsn>' fails for any reason:
catalog unreachable, wrong credentials, wrong database name, with the
underlying DuckDB/Postgres error as the message.
postgres://lakefront:lakefront@127.0.0.1:5432/lakefront
(the keyword/value form, postgres:dbname=lakefront host=127.0.0.1 port=5432 user=lakefront password=lakefront, is also accepted). Confirm the catalog
Postgres is actually reachable at that host and port (pg_isready, or just try
to connect with psql using the same values). Against the compose cluster,
remember the mapped host port is 55432, not 5432.
First write to a fresh lake fails after upgrading
Run resetLake (covered in the operations guide). It
drops both the catalog schema and the data directory so the new version can
create its schema from scratch. There is no in-place migration path before
1.0.
This is the fix if a write starts failing right after pulling a newer
lakefront onto an existing lake: lakefront is pre-1.0, and its catalog schema
DDL uses CREATE TABLE IF NOT EXISTS, so a table that already exists from an
older version is left exactly as it was, not migrated to whatever the new
version expects.
Everything hangs after the laptop slept
If queries and writes hang after the laptop wakes, restart the containers
(docker compose restart, or infra:down / infra:up for a dev lake you can
afford to reset).
On macOS, Docker-hosted Postgres can retain advisory-lock waiters after an interrupted operation, and Docker itself may become unresponsive. Killing the Bun process may not clear the waiters. If the hang persists after restarting the application, check whether the machine slept and whether the catalog and Docker are responding.
Replica files keep growing
Updates and deletes can leave unused space in replica ART indexes. The engine periodically rebuilds the indexes to reclaim it, so rebuild activity is expected on frequently updated boards. See replica index upkeep.
Cached count isn’t zero right after dropBoard
Poll for the state you expect, or accept the asynchrony. Don’t assert
stats().cached or cachedBoards() immediately after a drop in a test or
script; that’s asserting a race.
dropBoard (and evict directly) waits out any in-flight work on that board
before it actually detaches the replica file, so the cache converges after
the call returns, not necessarily inside the same tick.
Writes refused with ColumnTypeConflict
The write named a value for a base column (id or state) that doesn’t fit
that column’s fixed type, or a user column that was already inferred
at a narrower type and cannot be widened automatically. See the
schema guide for how column typing and widening work.
A write is refused with UnknownColumn on a board I didn’t configure
The board was created strict (createBoard(id, { strict: true })), which
makes it refuse writes naming an undeclared column, independent of the
engine-wide columns setting.
strict is stored in the catalog (lakefront_boards), not in the process
that created the board, so it applies on every node serving that board,
including ones that never set columns: "declared" themselves. See the
schema guide for how declared columns and strict work.
changes cursor returns resync
The change feed is tail-only: a cursor that falls behind retention, or connects
with an after value the retained window no longer covers, gets a resync
event instead of records. See the watch guide for the
retention window and the recovery contract.
MinIO bucket missing in cluster
Re-run bun run cluster:up. It re-runs minio-init along with everything
else, and the --ignore-existing flag makes it safe to run again against a
bucket that’s already there.
This is the fix if the lakefront bucket was deleted from under a running
cluster, or minio-init never completed. That one-shot container
(mc mb --ignore-existing) normally creates the bucket once, after MinIO
reports healthy, as part of cluster:up.