actualbudget/actual · error

Invalid parameters

Error message

Invalid parameters

What it means

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.

Source

Thrown at packages/sync-server/src/services/user-service.ts:131

  try {
    getAccountDb().transaction(() => {
      const ownerExists = getUserById(ownerId);
      if (!ownerExists) {
        throw new Error('New owner not found');
      }
      getAccountDb().mutate('UPDATE files set owner = ? WHERE owner = ?', [
        ownerId,
        oldUserId,
      ]);
    });
  } catch (error) {
    throw new Error(`Failed to transfer files: ${error.message}`);
  }
}

export function updateFileOwner(ownerId, fileId) {
  if (!ownerId || !fileId) {
    throw new Error('Invalid parameters');
  }
  try {
    const result = getAccountDb().mutate(
      'UPDATE files set owner = ? WHERE id = ?',
      [ownerId, fileId],
    );
    if (result.changes === 0) {
      throw new Error('File not found');
    }
  } catch (error) {
    throw new Error(`Failed to update file owner: ${error.message}`);
  }
}

export function getUserAccess(fileId, userId, isAdmin) {
  return getAccountDb().all(
    `SELECT users.id as userId, user_name as userName, files.owner, display_name as displayName
     FROM users

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Validate both ownerId and fileId are non-empty strings before calling updateFileOwner
  2. If ids come from an HTTP request, return a 400 to the client when they are missing instead of reaching the service
  3. Trace upstream lookups: if an id is undefined, fix the lookup that produced it, not this call
  4. Check for renamed request fields or payload-shape changes after upgrades

Example fix

// before
await updateFileOwner(body.ownerId, body.fileId);
// after
if (!body.ownerId || !body.fileId) {
  return res.status(400).json({ error: 'ownerId and fileId are required' });
}
await updateFileOwner(body.ownerId, body.fileId);
Defensive patterns

Strategy: validation

Validate before calling

function assertNonEmpty(value, name) {
  if (typeof value !== 'string' || value.length === 0) {
    throw new Error(`${name} is required`);
  }
}
assertNonEmpty(ownerId, 'ownerId');
assertNonEmpty(fileId, 'fileId');

Type guard

function hasValidIds(input) {
  return typeof input?.ownerId === 'string' && input.ownerId.length > 0 &&
         typeof input?.fileId === 'string' && input.fileId.length > 0;
}

Try / catch

try {
  updateFileOwner(ownerId, fileId);
} catch (e) {
  if (e.message.includes('Invalid parameters')) {
    throw new BadRequestError('ownerId and fileId are required');
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/e65738e74747d7e5. Report an issue: GitHub.