{"record":{"id":"98ce044ad138bd43","repo":"can1357/oh-my-pi","slug":"failed-to-open-auth-database-at-dbpath-after","errorCode":null,"errorMessage":"Failed to open auth database at '${dbPath}' after ${maxAttempts} attempts: ${lastBusyError?.message}","messagePattern":"Failed to open auth database at '(.+?)' after (.+?) attempts: (.+?)","errorType":"exception","errorClass":"AIError.ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/auth/sqlite-credential-store.ts","lineNumber":557,"sourceCode":"\t\t\t\ttry {\n\t\t\t\t\tawait fs.chmod(dbPath, 0o600);\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore chmod failures (e.g., Windows)\n\t\t\t\t}\n\t\t\t\tSqliteAuthCredentialStore.#ensureAuthCredentialRefreshLeasesTable(db);\n\t\t\t\treturn new SqliteAuthCredentialStore(db);\n\t\t\t} catch (err) {\n\t\t\t\tdb?.close();\n\t\t\t\tif (!isSqliteBusyError(err)) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\tlastBusyError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\tif (attempt < maxAttempts - 1) {\n\t\t\t\t\tawait Bun.sleep(baseDelayMs * 2 ** attempt);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new AIError.ConfigurationError(\n\t\t\t`Failed to open auth database at '${dbPath}' after ${maxAttempts} attempts: ${lastBusyError?.message}`,\n\t\t\t{ cause: lastBusyError },\n\t\t);\n\t}\n\n\tstatic #ensureAuthCredentialRefreshLeasesTable(db: Database): void {\n\t\tdb.run(`\n\t\t\tCREATE TABLE IF NOT EXISTS auth_credential_refresh_leases (\n\t\t\t\tcredential_id INTEGER PRIMARY KEY,\n\t\t\t\towner TEXT NOT NULL,\n\t\t\t\texpires_at_ms INTEGER NOT NULL,\n\t\t\t\tupdated_at INTEGER NOT NULL\n\t\t\t);\n\t\t\tCREATE INDEX IF NOT EXISTS idx_auth_credential_refresh_leases_expires ON auth_credential_refresh_leases(expires_at_ms);\n\t\t`);\n\t}\n\n\t/**","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth/sqlite-credential-store.ts#L539-L575","documentation":"SqliteAuthCredentialStore opens its Bun SQLite database with a bounded retry loop for SQLITE_BUSY contention. If the database still cannot be opened after maxAttempts, it throws AIError.ConfigurationError including the db path, attempt count, and the last busy error's message (cause preserved).","triggerScenarios":"The auth DB file is locked for longer than the retry window — another omp process holds a write lock, an antivirus/indexer has the file open, the DB lives on a network filesystem, or the file is corrupt so SQLite fails immediately on every attempt.","commonSituations":"Running multiple CLI sessions/workers that refresh auth concurrently; the auth directory on NFS/SMB/Dropbox-synced storage; stale lock from a crashed process; disk-full or permission issues surfacing as repeated open failures.","solutions":["Ensure no other process is holding the DB: close other omp/CLI sessions and retry","Move the auth database off network/synced filesystems to local disk (check the configured dbPath)","Check file permissions and free disk space at dbPath; delete a corrupt DB only if re-auth is acceptable","Increase maxAttempts/baseDelayMs in environments with heavy concurrent access"],"exampleFix":"// before: auth dir on NFS\nAUTH_DB=~/netdrive/omp/auth.db\n// after: local disk\nAUTH_DB=~/.omp/auth.db","handlingStrategy":"retry","validationCode":"// pre-check: can we open the DB and is it on a suitable filesystem?\nconst dbPath = getAuthDbPath();\nconst stat = await fs.stat(path.dirname(dbPath)).catch(() => null);\nif (!stat) throw new Error(`auth dir missing: ${path.dirname(dbPath)}`);\nif (isNetworkMount(path.dirname(dbPath))) logger.warn(\"auth DB on network mount; locks may time out\");","typeGuard":null,"tryCatchPattern":"try {\n  const store = new SqliteAuthCredentialStore(dbPath);\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && err.message.includes(\"Failed to open auth database\")) {\n    logger.error(\"Auth DB locked or unreadable\", { path: dbPath, cause: err.cause });\n    // surface to user: close other sessions or relocate dbPath\n  } else throw err;\n}","preventionTips":["Keep the auth database on local disk, not NFS/SMB/synced folders","Avoid running many concurrent CLI sessions against the same auth DB","Monitor disk space and file permissions on the auth directory","Treat this error as environmental: check for lock holders before retrying"],"tags":["sqlite","database-locked","auth","concurrency"],"backgroundTag":"database-is-locked","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}