---
title: Troubleshooting
description: 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](/guides/operations)). 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](/guides/operations#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](/guides/schema) 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](/guides/schema) 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](/guides/watch) 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`.
