---
title: "Troubleshooting"
description: "Verbatim errors and drop details — cause and fix."
---

> Documentation Index
> Fetch the complete documentation index at: https://logbun-docs.abshahin.workers.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

Titles match the message or `onEvent.detail` you will search for.

## `durable mode requires LogbunConfig.reliability with a persistent adapter`

**Cause:** `mode: 'durable'` (including via `ENTERPRISE_DEFAULTS`) without passing `reliability`.

**Fix:** Construct `FileReliabilityAdapter` or `CloudflareReliabilityAdapter` and pass it as `reliability`.

## `durable mode requires a persistent ReliabilityAdapter (MemoryReliabilityAdapter is not durable)`

**Cause:** Durable mode with `MemoryReliabilityAdapter` (`persistent: false`).

**Fix:** Use a filesystem or Durable Object adapter. Memory is volatile even with `enableJournal: true`.

## `database_per_tenant mode requires LogbunConfig.adapterFactory`

**Cause:** `tenancy.mode === 'database_per_tenant'` without `adapterFactory`. The pool never calls `new adapter.constructor(...)`.

**Fix:** Provide `adapterFactory` plus `resolveConnection`. See [Tenancy](/concepts/tenancy).

## `Configuration error: onQueueFull="drop" is not valid with mode="durable"`

**Cause:** Durable mode forbids dropping queued work on backpressure.

**Fix:** Use `onQueueFull: 'dlq'` (default) or switch to `mode: 'volatile'`.

## `AuditLogger is degraded — fireAsync unavailable`

**Cause:** Bootstrap failed. `ready` never rejects; `degraded` is `true`. `fire` drops with `detail: 'degraded'`.

**Fix:** Inspect `bootstrap_fail` / `degraded` events. Fix destination/reliability init. Construct a new logger; a degraded instance will not recover.

## `AuditLogger is not initialized — query unavailable`

Same family: `fireAsync unavailable` / `AuditLogger is not initialized` on flush, DLQ, and maintenance.

**Cause:** Degraded, not yet bootstrapped after a failed init, or already shut down.

**Fix:** Await `ready` and check `degraded`. After `shutdown()`, open a new logger (and a new adapter) to read persisted rows. Built-in adapters throw from `query` / `bulkInsert` / `prune` when closed.

## `tenantId is required when requireTenantId is true`

Or: `tenantId is required when tenancy.mode is "database_per_tenant"`.

**Cause:** Missing, empty, or whitespace-only `tenantId` (`isTenantIdPresent` is false).

**Fix:** Pass `tenantId` on the input, or `getTenantId` / `resolveTenantId` from a verified session. `fire` does not throw; it emits `drop` / `require_tenant_id`.

## `tenantId exceeds maxTenantIdBytes (256)`

**Cause:** UTF-8 length of `tenantId` is over `maxTenantIdBytes` (default 256). Tenant ids are never truncated.

**Fix:** Shorten the id or raise `maxTenantIdBytes`. `fire` drops (`max_tenant_id_bytes`); `fireAsync` rejects.

## `Failed to enqueue audit log (durable hard fail / backpressure)`

**Cause:** `fireAsync` admission returned `false` — journal and DLQ both failed, or durable backpressure could not admit.

**Fix:** Check `wal_fail`, `dlq_full`, `wal_full`, disk, and `getStatsDetailed()`. Do not assume the event is stored.

## `durable admission committed but maintenance scheduling failed`

`DurableAdmissionSchedulingError` with `durableAdmissionCommitted === true`.

**Cause:** Cloudflare journal/DLQ row committed; `getAlarm` / `setAlarm` failed.

**Fix:** Do **not** resubmit. Call `reliability.requestMaintenance()` after the scheduler recovers. Guard with `isDurableAdmissionSchedulingError`.

## `pool_exhausted`

**Cause:** `database_per_tenant` pool: every LRU entry is pinned (`maxActiveConnections`, default 50).

**Fix:** Raise the pool size, reduce concurrent tenant pins, or wait for in-flight queries/inserts to release.

## `Failed to resolve tenant adapter for tenantId "…"`

**Cause:** `resolveConnection` / `adapterFactory` / pin failed **before** `adapter.query` ran.

**Fix:** Inspect the wrapped message. SQL errors after a successful pin are **not** wrapped.

## `prune_incomplete`

**Cause:** SQLite/Turso batched prune hit 10_000 × 1_000 rows still remaining, or Turso omitted `rowsAffected`. ClickHouse prune does not throw this.

**Fix:** `runMaintenance()` rejects so you can schedule a follow-up pass. One call is not drain-until-idle.

## `Invalid namespace "…": must match /^[a-zA-Z0-9_-]{1,64}$/`

**Cause:** `LogbunConfig.namespace` or `FileReliabilityAdapter.namespace` failed `sanitizeNamespace`.

**Fix:** Alphanumeric, underscore, hyphen only; 1–64 characters. No `/`, `.`, or `..`.

## `FileReliabilityAdapter requires namespace`

**Cause:** Missing `namespace` on the filesystem adapter.

**Fix:** Pass a per-replica id. This field, not `LogbunConfig.namespace`, chooses `{dataDir}/{namespace}/`.

## `Invalid dataDir "…": path traversal ("..") is not allowed`

**Cause:** `dataDir` contains a `..` segment.

**Fix:** Use a path without `..`. Absolute paths are allowed.

## `encryptionKey string must be 64 hex characters or base64 of exactly 32 bytes`

**Cause:** Passphrase or wrong-length key. No silent SHA-256.

**Fix:** Pass 32 raw bytes, 64-char hex, or base64 of 32 bytes via `normalizeEncryptionKey`.

## WAL compact fails closed (`WALEncryptedLineError` / `WALPlaintextLineError` / `WALFailClosedError`)

**Cause:** Complete `e1:` line with wrong/missing key, or complete plaintext line while a key is configured. These `error.name` values are **not** root exports.

**Fix:** Use the same key that wrote the files. `flush()` / `runMaintenance()` reject; ciphertext is not rewritten away as junk JSON. Torn EOF crash tails (no newline) are skipped.

## `drop` / `pre_ready_buffer_full`

**Cause:** More than `maxPreReadyBuffer` (default 10_000) events before `ready`.

**Fix:** Await `ready` before emitting in durable mode. Durable-mode pre-ready accepts also emit `limit` / `pre_ready_volatile`.

## `limit` / `max_active_tenants`

**Cause:** A new tenant key would exceed `maxActiveTenants` (default 10_000). Durable persistent: written to DLQ (`dlq`). Volatile: dropped (`drop`).

**Fix:** Size for peak concurrent tenant keys. This is not a disk cap.

## `ClickHouseAdapter not initialized` / `BunSQLiteAdapter` closed

**Cause:** Calling adapter methods before `init` or after `close`.

**Fix:** Let `AuditLogger` own the lifecycle, or call `init()` yourself (must be idempotent). After `shutdown()`, construct a new adapter to read.

## Events vanish on Workers

**Cause:** Volatile `fire()` without `waitUntil`, or no DO journal. Detached `fire()` is not durable across isolate exit.

**Fix:** Durable: `CloudflareReliabilityAdapter` inside a DO + `fireAsync`. Volatile request runtimes: `await fireAsync(...); await flush()`. Hono wires `executionCtx.waitUntil` when present; Elysia needs `getWaitUntil`.

Source: https://logbun-docs.abshahin.workers.dev/troubleshooting/index.mdx
