actualbudget/actual · error
invalid-prefs
invalid-prefs
Error message
invalid-prefs
What it means
HTTP 400 from POST /server-prefs with `reason:'invalid-prefs'`. After the admin check, the endpoint destructures `prefs` from the body and requires it to be a truthy object; otherwise it rejects the request without calling `setServerPrefs`. This is a server-side schema validation for the prefs payload.
Source
Thrown at packages/sync-server/src/app-account.js:179
});
app.post('/server-prefs', (req, res) => {
const session = validateSession(req, res);
if (!session) return;
if (!isAdmin(session.user_id)) {
res.status(403).send({
status: 'error',
reason: 'forbidden',
details: 'permission-not-found',
});
return;
}
const { prefs } = req.body || {};
if (!prefs || typeof prefs !== 'object') {
res.status(400).send({ status: 'error', reason: 'invalid-prefs' });
return;
}
setServerPrefs(prefs);
res.send({ status: 'ok', data: {} });
});
app.get('/validate', (req, res) => {
const session = validateSession(req, res);
if (session) {
const user = getUserInfo(session.user_id);
if (!user) {
res.status(400).send({ status: 'error', reason: 'User not found' });
return;
}
res.send({View on GitHub (pinned to d4334cb6e6)
Solutions
- Wrap the settings in a `prefs` key: `{"prefs": {"key": "value"}}` with Content-Type application/json.
- Validate on the client that `typeof prefs === 'object' && prefs !== null` before calling the endpoint.
- If req.body is empty, fix the request encoding/Content-Type so express.json() parses it.
Example fix
// before
await api.post('/server-prefs', { 'cloudFileId': 'x' });
// after
await api.post('/server-prefs', { prefs: { 'cloudFileId': 'x' } }); Defensive patterns
Strategy: validation
Validate before calling
function isValidPrefsPayload(body) {
return body != null && typeof body.prefs === 'object' && body.prefs !== null && !Array.isArray(body.prefs);
}
if (!isValidPrefsPayload({ prefs })) throw new Error('POST /server-prefs requires body { prefs: object }'); Type guard
function isPrefsBody(b) {
return typeof b === 'object' && b !== null && 'prefs' in b && typeof b.prefs === 'object';
} Try / catch
try {
await post('/server-prefs', { prefs }, jsonHeaders);
} catch (e) {
if (e.response?.data?.reason === 'invalid-prefs') throw new PayloadError('prefs must be a non-null object');
throw e;
} Prevention
- Always nest settings under a `prefs` key
- Serialize with JSON and set Content-Type: application/json
- Unit-test request payloads against a shared schema with the client
When it happens
Trigger: POST /server-prefs with a body missing the `prefs` key, `prefs: null`, `prefs` as a string/number/array-like, or a body that fails to parse so `req.body` is undefined (`req.body || {}` yields no prefs).
Common situations: Client sends `{}` instead of `{prefs:{...}}`; sends the prefs object at the top level; Content-Type not application/json so req.body is empty; automation sending form-encoded data.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid catalog format: expected an array
- Field "${field}" does not exist on table ${table}: ${JSON.st
- "${field}" is required for table "${table}": ${JSON.stringif
- Invalid dashboard.widgets data type: it must be an array of
- validation-error
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/add1544ea833ff23.
Report an issue: GitHub.