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

  1. Send the original export object (as produced by the export endpoint / exportDb) — an object keyed by table names — not an array or raw string.
  2. 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)})`.
  3. Check the export file's top-level shape: it must start with `{`; if it starts with `[`, wrap or re-export it correctly before importing.
  4. 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

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/622f91e6b05609d6. Report an issue: GitHub.