Skip to content

Troubleshoot startup, native modules, auth, and migrations

View as Markdown

Preserve the exact error before changing dependencies or data. The signal usually belongs to one boundary: target, native runtime, migration guard, request semantics, authority, origin policy, or storage.

SignalInspect nextTypical correction
APP_SERVER_UNREACHABLEResolved CLI URL, network path, and API outputRestore reachability or fix --api-url
Could not locate the bindings fileNode version and installed better-sqlite3 packageRebuild the native addon in the API package
sapporta init rejects the pnpm versionpnpm --version on the machine running initUpgrade to pnpm 11 with corepack use pnpm@11
Frontend type error reaches the browserRoot typecheck script and tsc --noEmit outputRun pnpm typecheck; a green vite build is not a type check
SAPPORTA_DATA_DIR is not setEnvironment of the server or db:* commandSet it to the directory that holds sqlite.db
Migration readiness failureDatabase: line in the error, migration files, ledgerFix SAPPORTA_DATA_DIR, restore files, or apply the reviewed migration
Structured 400 on a list routeColumn, operator, and semantic query valueFix the strict filter; keep the intended predicate
unauthenticated or token errorTarget, active workspace, expiry, revocationCreate or pass the correct scoped token
Browser CORS or callback errorPublic app URL and exact origin listAlign the configured topology
Data disappears after restartDatabase: line at startup and the volume mountPoint SAPPORTA_DATA_DIR at durable storage and restore backup

Start by preserving the full error and running read-only discovery:

Terminal window
pnpm exec sapporta endpoints list
pnpm exec sapporta tables show tasks
SAPPORTA_DATA_DIR=data pnpm --filter ./packages/api db:check

For a migration readiness failure, read the database path first. The server prints the database it opened after its ready line, and the readiness error names the database it checked:

Sapporta migrations are not ready.
Database: /srv/tasks/data/sqlite.db

A SAPPORTA_DATA_DIR that names the wrong directory produces exactly the failure of a database that was never migrated. The value can come from .env.development, from a tool such as mise or direnv, or from the shell; confirm the path before applying a migration or restoring files. db:migrate migrates the database in its own environment’s SAPPORTA_DATA_DIR, so run it with the value the server uses.

For a native binding failure after changing Node or reinstalling packages, rebuild the addon where the API package installed it:

Terminal window
pnpm --filter ./packages/api rebuild better-sqlite3
pnpm build

For a frontend type error that a build did not report, run the type checker directly:

Terminal window
pnpm typecheck

vite build transpiles with esbuild, which erases types without checking them, so a successful build says nothing about whether the frontend compiles. Grid and lookup generics fail at the type level and nowhere else. A project generated before the root typecheck script existed runs pnpm --filter ./packages/frontend exec tsc --noEmit and should add the script to its root package.json.

A project generated before the root declared a CLI reports [ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL] Command "sapporta" not found from the project root. pnpm exec searches the current package and then PATH, never an ancestor, so either add @sapporta/server to the root devDependencies at the spec packages/api resolves, or run the command from the package that declares it: pnpm --filter ./packages/api exec sapporta ....

For a bad filter, inspect the generated endpoint and keep an explicit operator:

Terminal window
pnpm exec sapporta endpoints show "GET /api/tables/tasks"
pnpm exec sapporta rows list tasks \
--where '{"status":{"eq":"open"}}'

Dropping a rejected filter and retrying would change the data question and can return a much larger visible result set.

For an auth failure, confirm the API URL before replacing the token. A token is bound to one user and workspace. Do not diagnose workspace-user access by opening the SQLite file directly.

Troubleshooting is complete when the original operation succeeds under its intended scope. Keep rejected filters and authority checks strict; a broad retry changes the question and may widen the result.