{"record":{"id":"2fa43879accfc56f","repo":"actualbudget/actual","slug":"invalid-access-key","errorCode":null,"errorMessage":"Invalid access key","messagePattern":"Invalid access key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/app-simplefin/app-simplefin.js","lineNumber":322,"sourceCode":"      error_code: 'SERVER_DOWN',\n      status: 'rejected',\n      reason: 'There was an error communicating with SimpleFIN.',\n    },\n  });\n}\n\nconst ACCESS_KEY_FORMAT = /^.*\\/\\/.*:.*@.*$/;\n\nfunction parseAccessKey(accessKey) {\n  let scheme = null;\n  let rest = null;\n  let auth = null;\n  let username = null;\n  let password = null;\n  let baseUrl = null;\n  if (!accessKey || !ACCESS_KEY_FORMAT.test(accessKey)) {\n    console.log('Invalid SimpleFIN access key');\n    throw new Error(`Invalid access key`);\n  }\n  [scheme, rest] = accessKey.split('//');\n  [auth, rest] = rest.split('@');\n  [username, password] = auth.split(':');\n  baseUrl = `${scheme}//${rest}`;\n  return {\n    baseUrl,\n    username,\n    password,\n  };\n}\n\nfunction decodeClaimUrl(base64Token) {\n  const decoded = Buffer.from(base64Token, 'base64').toString();\n\n  let url;\n  try {\n    url = new URL(decoded);","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-simplefin/app-simplefin.js#L304-L340","documentation":"parseAccessKey validates a SimpleFIN access key against ACCESS_KEY_FORMAT before parsing it into scheme/auth/baseUrl parts. If the key is missing or doesn't match the expected format (roughly `https://user:pass@domain`), it throws 'Invalid access key'. The server never even attempts a network call with a malformed key.","triggerScenarios":"Providing an empty/undefined access key, or a key that isn't a SimpleFIN setup-token-style URL (e.g. pasting a plain token, a token with missing scheme or credentials, or one that has been truncated/corrupted) to parseAccessKey via the SimpleFIN setup/claim flow.","commonSituations":"User pasted only the temporary connection token instead of the full access key URL; key copied with whitespace or partially; using a key from a different service; the claim step failed earlier and an error string was stored as the key.","solutions":["Obtain a fresh access key from https://bridge.simplefin.org/auth/login and paste the complete key URL exactly as provided.","Check the stored key starts with `https://` and contains `user:pass@host` parts; re-enter it if truncated.","Make sure the claim step succeeded before persisting the key — a non-key string (e.g. an error message) will fail this check.","Trim surrounding whitespace/quotes when storing or passing the key."],"exampleFix":"// before\nawait setupSimplefin('abc123token');\n\n// after\nawait setupSimplefin('https://demo:TOKEN@bridge.simplefin.org/sfin/xxx');","handlingStrategy":"validation","validationCode":"const ACCESS_KEY_RE = /^https:\\/\\/[^:]+:[^@]+@.+$/;\nif (!accessKey || !ACCESS_KEY_RE.test(accessKey.trim())) {\n  throw new Error('Not a valid SimpleFIN access key URL');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim and validate the key at input time (before storing it).","Ensure the claim step succeeded and returned a key URL, not an error string.","Always copy the full https://user:pass@host key from bridge.simplefin.org."],"tags":["simplefin","validation","credentials"],"backgroundTag":"invalid-api-key","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}