Skip to content
Lakefront
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

Last updated on September 10, 2026

Was this page helpful?