Errors

Last updated 29 October 2026

View .md

The error classes the package throws, each kind, when it happens and what to do.

Every class extends UrsulaError and is exported by @tonbo/sqlite-ursula and /tonbo; TonboError by /tonbo alone. Any other error, such as a constraint violation or a syntax error, is node:sqlite’s, unchanged. Symptoms and their fixes are on Troubleshooting.

UrsulaError

class UrsulaError extends Error {
  readonly kind: UrsulaErrorKind;
  readonly action: "retry" | "reopen" | "stop" | "fix";
  readonly cause?: unknown;
  readonly code?: string;    // node:sqlite's, when cause is its error
  readonly errcode?: number;
  readonly errstr?: string;
}

kind names what failed and action what to do: branch on action. cause is the error the failure surfaced as, usually SQLite’s, whose code, errcode and errstr are copied, so code that reads them keeps working. Network failures never throw from statements or synced(): they wait.

import { UrsulaError } from "@tonbo/sqlite-ursula/tonbo";

try {
  db.prepare("INSERT INTO notes(body) VALUES (?)").run(body);
} catch (error) {
  if (!(error instanceof UrsulaError)) throw error; // a constraint, a syntax error
  if (error.action === "retry") await db.synced(); // then run the transaction again
  else throw error; // reopen, stop or fix
}

Actions

UrsulaErrorAction. The extension names each failure’s kind, action and class, the error to throw, through ursula_classify since 0.11.2, so a kind this page does not list, from a newer extension, carries the extension’s action; 0.11.1 said fix for such a kind. Messages are the extension’s too.

ActionWhat to do
retryNothing was lost and the database stays usable. After backlog_full, await synced() and run the transaction again; after a failed open(), call it again later.
reopenClose every connection of the database and open() it again.
stopAnother owner took the stream over. Stop using the database, and never reopen it in a loop: opening it takes the stream back.
fixIt cannot succeed as asked. Fix the URL, the setup, the stream, the key or the transaction, then open the database again.

UrsulaErrorKind is every kind on this page: the union of WriteRefusedKind, ResetKind, UnavailableKind, SetupKind and TonboKind.

UrsulaWriteRefusedError

A write or COMMIT refused with nothing committed: SQLite rolled the whole transaction back, and the database stays usable. Its errcode is 7178, SQLITE_IOERR_AUTH, and status().refused keeps the last one.

KindActionWhenWhat to do
backlog_fullretryMore than maxPendingBytes of commits wait for the stream.Await synced(), then run the transaction again.
unsupportedfixA write the extension does not capture: in EXCLUSIVE locking mode, or a commit that leaves WAL mode or 4 KiB pages.Leave journal_mode, the page size and the locking mode as open() sets them.
too_largefixThe commit holds more bytes of pages than the commit limit (see Limits).Split the transaction, or raise URSULA_VFS_MAX_COMMIT_BYTES.

UrsulaResetError

The database was reset. Every statement of it throws this, reads included (errcode 266 for a read, 778 for a write), synced() rejects with it, and the reset listeners get it. See After a reset.

KindActionWhenWhat to do
fencedstopAnother process opened the database and took the stream over.Stop. Find the second writer before you open the database again.
stalereopenAnother owner wrote or claimed the stream since this cache's claim, found once a provisional open reached the stream, or the stream sat idle past the server's producer expiry.Open it again: the new open takes over with the pending commits.
rewoundreopenThe stream's history moved back past commits this database holds, such as a restore to an earlier point.Open it again; the old cache goes to salvage/ when it holds data.
deletedfixThe stream was deleted.Create the database again, or stop.
local_damagereopenThe host's disk failed the extension: a failed fsync, a lost WAL page or a log write it could not cut.Check the disk, then open it again.
stream_statefixThe stream is in a state replication cannot continue on.Fix the stream, then open it again.
internalreopenAn internal failure of the extension.Open it again.

UrsulaUnavailableError

open() found no trusted state in time: its signal fired while the stream, or for an open by name the Tonbo API, did not answer as it must. kind is the last condition it met, or cancelled when it met none. A token provider that handed out no token in time rejects the open with unavailable, its last error as the cause. From importSqlite() every kind says fix, since the stream may hold the import’s claim.

KindActionWhenWhat to do
unreachableretryNo connection to the stream or the Tonbo API.Check the network, then retry.
unavailableretryThe server answered 5xx or no definite answer, a database was still being created, or a token provider handed out no token.Retry later.
rate_limitedretryThe server answered 429.Retry later.
unauthorizedfixThe stream answered 401: the token is missing, expired or revoked.Fix the token or the key. After a token provider’s failed call the action is retry, unless it failed for good.
payment_requiredfixThe stream answered 402.See When the balance runs out.
forbiddenfixThe stream answered 403.Check the key's scope and the account's access.
cancelledretryThe signal fired before the open met any condition.Retry with a longer signal.

UnavailableKind also names wrong_cluster, but the package throws it as an UrsulaSetupError.

UrsulaSetupError

open(), resolveDatabase() or importSqlite() cannot succeed as asked, or a database that retired was asked for synced() or status(). Its message says what to change.

KindActionWhenWhat to do
invalid_argumentfixAn option, a file to import, or an answer of the Tonbo API the package cannot use, or an open by name with a second API key while the first key’s tokens serve (since 0.11.2). The message names which.Fix what it names. For a second key, use one key per process (see One token per process).
invalid_urlfixNot a stream URL, or one that would get the API key’s tokens over plain http:// to a host other than loopback.Use the database’s https:// URL.
invalid_namefixAn empty database name (since 0.11.1).Pass the name (see Names).
not_foundfixThe stream is missing. Over a cache that holds data, only recreate opens it.Create the database (see Manage databases).
in_useretryAnother process on this host holds the stream's cache, or its binding under another cache root of this process still drains.Retry once the other one has let go.
bound_elsewherefixThe stream is open in this process under another cache root, with connections open.Close it there first, or pass its dir.
local_setupfixThe cache root, a file in it, a file to import or the login file cannot be read or written, or the extension library is older than the package, which loadUrsulaVfs() refuses since 0.11.2.Fix the path or its permissions, or load the library of the package’s release (see SQLITE_URSULA_VFS).
stream_formatfixThe stream holds another content type: it is not a database's stream.Check the URL.
no_server_identityfixAn answer without Ursula-Protocol and Ursula-Cluster-Id, such as a proxy’s.Check the URL and anything in front of the server.
protocol_mismatchfixA server of another release line.Use a package release of the server’s line: the exact version these docs name, for Tonbo.
wrong_clusterfixThe cache was built on another deployment than the server's.Pass another dir, or remove that stream’s cache.
stream_statefixThe stream refuses opens: an import runs on it, or one failed after it claimed the stream.Wait for the import, or delete and create the database again.
claim_racesretryThe claim lost to other processes claiming the stream at the same time.Make sure one process opens it, then retry.
not_boundfixThe database retired: its last connection closed.Open it again with open().
internalreopenAn internal failure of the extension.Open it again.

TonboError

From /tonbo, since 0.11.1. A key, a login or a database to fix: the action is always fix. fix holds what to do, the variable to set or the command to run, and the message ends with it. requestId is the Tonbo API’s id of the answer that failed, when one did; quote it to support.

class TonboError extends UrsulaError {
  readonly kind: TonboKind;
  readonly fix: string;
  readonly requestId: string | undefined;
}
KindWhenfix
missing_credentialsNo apiKey, no TONBO_API_KEY and no login file.Set TONBO_API_KEY, or run: tonbo login
credentials_refusedThe login file is a symlink, not a regular file, or open to group or others. It is never read.Run: chmod 600 <path>, or replace the file
invalid_api_keyThe API refused the key (401), the token endpoint refused it a token, the key cannot read the database (403), TONBO_API_KEY holds no usable key, or the login expired or is not one this package reads.Pass a valid apiKey, set TONBO_API_KEY, or Run: tonbo login, after the key’s source; for a 403, Use an API key that can read database "<name>"
database_not_foundThe key's account has no database of that name, or it is being deleted.Run: tonbo database create <name>