{"record":{"id":"889020984fa2ff06","repo":"actualbudget/actual","slug":"key-not-found","errorCode":null,"errorMessage":"key not found","messagePattern":"key not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"packages/sync-server/src/app-secrets.js","lineNumber":89,"sourceCode":"      reason: 'not-admin',\n      details: 'You have to be admin to manage global secrets',\n    });\n    return;\n  }\n\n  const secretFileId = perBudgetFile ? fileId : null;\n  secretsService.set(name, value, secretFileId);\n\n  res.status(200).send({ status: 'ok' });\n});\n\napp.delete('/:name', async (req, res) => {\n  const name = req.params.name;\n  const fileId = req.get('X-Actual-File-Id');\n  const perBudgetFile = fileId != null;\n\n  if (!(name in SecretName)) {\n    res.status(404).send('key not found');\n    return;\n  }\n\n  if (!perBudgetFile) {\n    if (!canManageGlobalSecrets(res.locals.user_id)) {\n      res.status(403).send({\n        status: 'error',\n        reason: 'not-admin',\n        details: 'You have to be admin to manage global secrets',\n      });\n      return;\n    }\n\n    secretsService.reset(name);\n    res.status(200).send({ status: 'ok' });\n    return;\n  }\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-secrets.js#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"Cleanup scripts iterating over guessed key names; typos like 'gocardelss' in ops runbooks; version skew where the enum changed between deployments.","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."],"exampleFix":"// before\ndelete('/secrets/gocardless_secet_id') // 404\n// after\ndelete('/secrets/gocardless_secret_id') // 200 {status:'ok'}","handlingStrategy":"validation","validationCode":"function isKnownSecretName(name) {\n  return ['gocardless_secret_id','gocardless_account_id','pluggyai_client_id','pluggyai_client_secret'].includes(name);\n}","typeGuard":"function isSecretName(name) {\n  return typeof name === 'string' && name in SecretName;\n}","tryCatchPattern":"if (!isKnownSecretName(name)) return; // skip, would 404\nconst res = await fetch(`/secrets/${encodeURIComponent(name)}`, { method: 'DELETE' });\nif (res.status === 404) { /* name not in enum or key absent — log and continue */ }","preventionTips":["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"],"tags":["http-404","validation","secrets","delete"],"backgroundTag":"resource-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}