actualbudget/actual · warning
key not found
Error message
key not found
What it means
DELETE /secrets/:name first validates the name against SecretName and responds HTTP 404 'key not found' when the name is not a known secret name. Note this endpoint conflates 'unknown name' with 'not found' — the 404 is returned before any permission or existence checks, so an unknown key is indistinguishable from a valid but absent key by status text alone.
Source
Thrown at packages/sync-server/src/app-secrets.js:89
reason: 'not-admin',
details: 'You have to be admin to manage global secrets',
});
return;
}
const secretFileId = perBudgetFile ? fileId : null;
secretsService.set(name, value, secretFileId);
res.status(200).send({ status: 'ok' });
});
app.delete('/:name', async (req, res) => {
const name = req.params.name;
const fileId = req.get('X-Actual-File-Id');
const perBudgetFile = fileId != null;
if (!(name in SecretName)) {
res.status(404).send('key not found');
return;
}
if (!perBudgetFile) {
if (!canManageGlobalSecrets(res.locals.user_id)) {
res.status(403).send({
status: 'error',
reason: 'not-admin',
details: 'You have to be admin to manage global secrets',
});
return;
}
secretsService.reset(name);
res.status(200).send({ status: 'ok' });
return;
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Use an exact SecretName value from the running server's secrets-service source.
- Check whether the key exists first with GET /secrets/:name to distinguish enum errors from absent keys.
- Fix URL encoding of the name path segment in your client.
- Align client and server versions so the secret name set matches.
Example fix
// before
delete('/secrets/gocardless_secet_id') // 404
// after
delete('/secrets/gocardless_secret_id') // 200 {status:'ok'} Defensive patterns
Strategy: validation
Validate before calling
function isKnownSecretName(name) {
return ['gocardless_secret_id','gocardless_account_id','pluggyai_client_id','pluggyai_client_secret'].includes(name);
} Type guard
function isSecretName(name) {
return typeof name === 'string' && name in SecretName;
} Try / catch
if (!isKnownSecretName(name)) return; // skip, would 404
const res = await fetch(`/secrets/${encodeURIComponent(name)}`, { method: 'DELETE' });
if (res.status === 404) { /* name not in enum or key absent — log and continue */ } Prevention
- Validate the name against the SecretName enum before DELETE
- URL-encode the path segment
- Prefer checking existence via GET before deleting
- Pin integration names to the server version
When it happens
Trigger: DELETE /secrets/<name> where <name> is misspelled or not in the SecretName enum; deleting a renamed provider secret name; URL-encoding issues mangling the name in the path; a client using a secret name from an older/newer server version.
Common situations: Cleanup scripts iterating over guessed key names; typos like 'gocardelss' in ops runbooks; version skew where the enum changed between deployments.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- invalid-secret-name
- invalid-file-id
- Invalid --name: must be a non-empty string.
- No update fields provided. Use --name or --offbudget.
- Invalid cutoff date: expected a valid date (e.g. YYYY-MM-DD)
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/889020984fa2ff06.
Report an issue: GitHub.