Stirling-Tools/Stirling-PDF · error · Error
Database not initialized
Error message
Database not initialized
What it means
`ensureDB()` lazily calls `init()` (which opens IndexedDB via `indexedDB.open`) and then re-checks `this.db`. This throw means `init()` resolved without ever setting `this.db` — the `onsuccess` callback never ran. IndexedDB open can fail outright (private/incognito mode, quota exceeded, the browser disabling storage) and `request.onerror` rejects, but if `init()` is rejected the rejection propagates before this line; reaching the throw means `init()` settled to undefined without assigning `this.db`.
Source
Thrown at frontend/editor/src/core/services/automationStorage.ts:54
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains(this.storeName)) {
const store = db.createObjectStore(this.storeName, { keyPath: "id" });
store.createIndex("name", "name", { unique: false });
store.createIndex("createdAt", "createdAt", { unique: false });
}
};
});
}
async ensureDB(): Promise<IDBDatabase> {
if (!this.db) {
await this.init();
}
if (!this.db) {
throw new Error("Database not initialized");
}
return this.db;
}
async saveAutomation(
automation: Omit<AutomationConfig, "id" | "createdAt" | "updatedAt">,
): Promise<AutomationConfig> {
const db = await this.ensureDB();
const timestamp = new Date().toISOString();
const automationWithMeta: AutomationConfig = {
id: `automation-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
...automation,
createdAt: timestamp,
updatedAt: timestamp,
};
View on GitHub (pinned to 9ef20dcab8)
Solutions
- Call `automationStorage.init()` once at app startup and surface its failure to the user (banner: 'automations unavailable in this browser mode') instead of deferring to first-use.
- Detect private/incognito mode at startup and disable the automation feature gracefully rather than letting `ensureDB` throw.
- Wrap `onupgradeneeded` logic defensively (guard `db.objectStoreNames.contains` and index existence) so a version bump cannot abort the open.
- Fall back to an in-memory store when IndexedDB is unavailable so reads/writes still work for the session.
Example fix
// before
async ensureDB(): Promise<IDBDatabase> {
if (!this.db) {
await this.init();
}
if (!this.db) {
throw new Error("Database not initialized");
}
return this.db;
}
// after
async ensureDB(): Promise<IDBDatabase> {
if (!this.db) await this.init();
if (!this.db) {
throw new Error("Database not initialized (IndexedDB may be disabled or in private mode)");
}
return this.db;
} Defensive patterns
Strategy: validation
Validate before calling
// Detect whether IndexedDB is usable before relying on automationStorage
async function indexedDBAvailable(): Promise<boolean> {
try {
if (typeof indexedDB === "undefined") return false;
const req = indexedDB.open("__probe__");
return await new Promise<boolean>((resolve) => {
req.onsuccess = () => { req.result.close(); indexedDB.deleteDatabase("__probe__"); resolve(true); };
req.onerror = () => resolve(false);
});
} catch { return false; }
} Type guard
function isOpenDB(db: unknown): db is IDBDatabase {
return !!db && typeof (db as IDBDatabase).transaction === "function";
} Try / catch
try {
const db = await automationStorage.ensureDB();
await automationStorage.saveAutomation(automation);
} catch (e) {
if (e instanceof Error && e.message.startsWith("Database not initialized")) {
showBanner("Automations are unavailable in this browser mode (private/incognito or storage disabled).");
} else { throw e; }
} Prevention
- Initialise automationStorage at app startup and surface init failure immediately.
- Detect private/incognito mode and disable the automations feature rather than failing on first use.
- Defensively guard index creation in onupgradeneeded so a version bump can't abort the open.
- Maintain an in-memory fallback store so the session still works when IndexedDB is unavailable.
When it happens
Trigger: Calling `saveAutomation`/`getAllAutomations` (any method going through `ensureDB`) when the user is in private browsing where IndexedDB is blocked or ephemeral; when `onupgradeneeded` throws (e.g. `createIndex` on an existing index name) aborts the upgrade; or when `init()` was overwritten/monkeypatched to resolve without assigning `this.db`.
Common situations: Safari private mode (IndexedDB open silently fails or the DB evaporates on tab close); a `dbVersion` bump that makes `onupgradeneeded` fail mid-migration leaving no usable handle; Firefox/Chrome with site data blocked by the user; running under a test runner that stubs `indexedDB` incorrectly.
Related errors
- IndexedDB context not available
- No history chain found for file.
- Missing file data for ${stub.name || stub.id}
- File "${file.name}" not found in storage
- No valid files found in storage for ZIP download
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/1ee35ea7ddeda217.
Report an issue: GitHub.