decolua/9router · error
Invalid database payload
Error message
Invalid database payload
What it means
importDb performs a destructive restore: it wipes all tables (keeping _meta) inside a transaction and repopulates them from the given payload. Because the wipe is irreversible, the payload is validated first — it must be a non-null, non-array object; anything else (null, undefined, arrays, strings, numbers) throws this error before the database is touched.
Source
Thrown at src/lib/db/index.js:98
apiKeys: db.all(`SELECT * FROM apiKeys`).map((r) => ({ id: r.id, key: r.key, name: r.name, machineId: r.machineId, isActive: r.isActive === 1, createdAt: r.createdAt })),
combos: db.all(`SELECT * FROM combos`).map((r) => ({ id: r.id, name: r.name, kind: r.kind, models: parseJson(r.models, []), createdAt: r.createdAt, updatedAt: r.updatedAt })),
modelAliases: {},
customModels: [],
mitmAlias: {},
pricing: {},
};
for (const r of db.all(`SELECT key, value FROM kv WHERE scope = 'modelAliases'`)) out.modelAliases[r.key] = parseJson(r.value);
for (const r of db.all(`SELECT key, value FROM kv WHERE scope = 'customModels'`)) out.customModels.push(parseJson(r.value));
for (const r of db.all(`SELECT key, value FROM kv WHERE scope = 'mitmAlias'`)) out.mitmAlias[r.key] = parseJson(r.value);
for (const r of db.all(`SELECT key, value FROM kv WHERE scope = 'pricing'`)) out.pricing[r.key] = parseJson(r.value);
return out;
}
export async function importDb(payload) {
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
throw new Error("Invalid database payload");
}
const db = await getAdapter();
db.transaction(() => {
// Wipe all tables (keep _meta)
db.run(`DELETE FROM settings`);
db.run(`DELETE FROM providerConnections`);
db.run(`DELETE FROM providerNodes`);
db.run(`DELETE FROM proxyPools`);
db.run(`DELETE FROM apiKeys`);
db.run(`DELETE FROM combos`);
db.run(`DELETE FROM kv WHERE scope IN ('modelAliases', 'customModels', 'mitmAlias', 'pricing')`);
// Settings
if (payload.settings) {
db.run(`INSERT INTO settings(id, data) VALUES(1, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`, [stringifyJson(payload.settings)]);
}
View on GitHub (pinned to 90b52e06ff)
Solutions
- Send the original export object (as produced by the export endpoint / exportDb) — an object keyed by table names — not an array or raw string.
- Parse the uploaded file as JSON on the client and pass reqBody as an object: `const payload = JSON.parse(fileText); await fetch('/api/db/import', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload)})`.
- Check the export file's top-level shape: it must start with `{`; if it starts with `[`, wrap or re-export it correctly before importing.
- In the API handler, validate the parsed body and return 400 before calling importDb so users get a friendly message instead of a thrown error.
Example fix
// before
await fetch('/api/db/import', { method: 'POST', body: JSON.stringify(rows) }); // rows is an array
// after
const payload = JSON.parse(exportText); // { settings: [...], accounts: [...], ... }
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) throw new Error('Export file is not a valid DB export');
await fetch('/api/db/import', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); Defensive patterns
Strategy: validation
Validate before calling
function isImportableDbPayload(p) {
return !!p && typeof p === 'object' && !Array.isArray(p);
}
// in the POST handler:
const payload = await req.json().catch(() => null);
if (!isImportableDbPayload(payload)) return res.status(400).json({ error: 'Body must be a DB export object' }); Type guard
function isDbExportPayload(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v)
&& Object.values(v).every(t => t === undefined || Array.isArray(t));
} Try / catch
try {
await importDb(payload);
} catch (err) {
if (String(err.message) === 'Invalid database payload') {
return res.status(400).json({ error: 'Upload a DB export object (JSON object keyed by table), not an array or string' });
}
throw err;
} Prevention
- Always import from a file produced by the matching export endpoint; never hand-roll the payload shape.
- Parse and sanity-check the JSON client-side (top level must be `{`) before POSTing.
- Set Content-Type: application/json on import requests so the body parses into an object, not a string.
- Warn users before import that all tables are wiped — combine with a backup/export call so a bad payload costs nothing.
- Reject empty or zero-byte uploads at the UI level before reaching the API.
When it happens
Trigger: POSTing a database-import request whose JSON body is null, an array (e.g. a bare export of rows), a plain string/number, or an empty body so the handler passes undefined into importDb.
Common situations: A client uploaded an export file whose top level is an array instead of the expected {settings:[...], ...} object; a fetch call forgot `Content-Type: application/json` so the handler received an unparsed string; an empty-file upload produced null; a script piped the wrong file (e.g. usage.json instead of the DB export).
Related errors
- Failed to import database
- Access token is required
- Machine ID is required
- Invalid token format. Token appears too short.
- Xquik queryType must be Latest or Top
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/622f91e6b05609d6.
Report an issue: GitHub.