{"record":{"id":"e65738e74747d7e5","repo":"actualbudget/actual","slug":"invalid-parameters","errorCode":null,"errorMessage":"Invalid parameters","messagePattern":"Invalid parameters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/services/user-service.ts","lineNumber":131,"sourceCode":"  try {\n    getAccountDb().transaction(() => {\n      const ownerExists = getUserById(ownerId);\n      if (!ownerExists) {\n        throw new Error('New owner not found');\n      }\n      getAccountDb().mutate('UPDATE files set owner = ? WHERE owner = ?', [\n        ownerId,\n        oldUserId,\n      ]);\n    });\n  } catch (error) {\n    throw new Error(`Failed to transfer files: ${error.message}`);\n  }\n}\n\nexport function updateFileOwner(ownerId, fileId) {\n  if (!ownerId || !fileId) {\n    throw new Error('Invalid parameters');\n  }\n  try {\n    const result = getAccountDb().mutate(\n      'UPDATE files set owner = ? WHERE id = ?',\n      [ownerId, fileId],\n    );\n    if (result.changes === 0) {\n      throw new Error('File not found');\n    }\n  } catch (error) {\n    throw new Error(`Failed to update file owner: ${error.message}`);\n  }\n}\n\nexport function getUserAccess(fileId, userId, isAdmin) {\n  return getAccountDb().all(\n    `SELECT users.id as userId, user_name as userName, files.owner, display_name as displayName\n     FROM users","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/services/user-service.ts#L113-L149","documentation":"updateFileOwner validates its arguments up front and throws 'Invalid parameters' if either ownerId or fileId is falsy (null, undefined, empty string, 0). It is a guard to prevent issuing a meaningless UPDATE against the files table. No database access happens when this fires.","triggerScenarios":"Calling updateFileOwner(ownerId, fileId) with either argument missing — e.g. an API request body that omitted ownerId or fileId, an id variable that was undefined because an earlier lookup failed, or an empty string from an unset environment/config value.","commonSituations":"HTTP handlers forwarding req.body fields without validation; a getFileById/user lookup returning null earlier in the chain and the null being passed onward; refactors renaming fields so the old property name resolves to undefined.","solutions":["Validate both ownerId and fileId are non-empty strings before calling updateFileOwner","If ids come from an HTTP request, return a 400 to the client when they are missing instead of reaching the service","Trace upstream lookups: if an id is undefined, fix the lookup that produced it, not this call","Check for renamed request fields or payload-shape changes after upgrades"],"exampleFix":"// before\nawait updateFileOwner(body.ownerId, body.fileId);\n// after\nif (!body.ownerId || !body.fileId) {\n  return res.status(400).json({ error: 'ownerId and fileId are required' });\n}\nawait updateFileOwner(body.ownerId, body.fileId);","handlingStrategy":"validation","validationCode":"function assertNonEmpty(value, name) {\n  if (typeof value !== 'string' || value.length === 0) {\n    throw new Error(`${name} is required`);\n  }\n}\nassertNonEmpty(ownerId, 'ownerId');\nassertNonEmpty(fileId, 'fileId');","typeGuard":"function hasValidIds(input) {\n  return typeof input?.ownerId === 'string' && input.ownerId.length > 0 &&\n         typeof input?.fileId === 'string' && input.fileId.length > 0;\n}","tryCatchPattern":"try {\n  updateFileOwner(ownerId, fileId);\n} catch (e) {\n  if (e.message.includes('Invalid parameters')) {\n    throw new BadRequestError('ownerId and fileId are required');\n  }\n  throw e;\n}","preventionTips":["Validate request bodies at the route layer before calling service functions","Never forward results of failed lookups (null/undefined ids) into service calls","Fix field renames in payloads after upgrades","Use a shared assert-id helper for all id parameters"],"tags":["sync-server","validation","arguments","guard-clause"],"backgroundTag":"missing-required-parameter","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}