actualbudget/actual · error · Error

Cannot use both --data and --file

Error message

Cannot use both --data and --file

What it means

readJsonInput accepts JSON payload from either an inline --data string or a --file path (with '-' meaning stdin). Supplying both is ambiguous, so it throws immediately before reading anything. This is a mutual-exclusion guard on the command's input options.

Source

Thrown at packages/cli/src/input.ts:8

import { readFileSync } from 'fs';

export function readJsonInput(cmdOpts: {
  data?: string;
  file?: string;
}): unknown {
  if (cmdOpts.data && cmdOpts.file) {
    throw new Error('Cannot use both --data and --file');
  }
  if (cmdOpts.data) {
    return JSON.parse(cmdOpts.data);
  }
  if (cmdOpts.file) {
    const content =
      cmdOpts.file === '-'
        ? readFileSync(0, 'utf-8')
        : readFileSync(cmdOpts.file, 'utf-8');
    return JSON.parse(content);
  }
  throw new Error('Either --data or --file is required');
}

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Remove --data and keep --file (or vice versa) in the invocation.
  2. If building the command in a script, make the branches mutually exclusive (if/else) rather than appending both flags.
  3. Use --file - with piped stdin instead of embedding large JSON in --data.

Example fix

// before
actual-cli transactions --sync-id $ID --data '[...]' --file txns.json
// after
actual-cli transactions --sync-id $ID --file txns.json
Defensive patterns

Strategy: validation

Validate before calling

const sources = [cmdOpts.data, cmdOpts.file].filter(Boolean);
if (sources.length > 1) throw new Error('Pass either --data or --file, not both.');
if (sources.length === 0) throw new Error('Pass --data or --file (- for stdin).');

Try / catch

try {
  const json = readJsonInput({ data: opts.data, file: opts.file });
} catch (err) {
  if (err instanceof Error && err.message === 'Cannot use both --data and --file') {
    console.error('Choose one input source: --data or --file.');
    process.exit(2);
  }
  throw err;
}

Prevention

When it happens

Trigger: A command invocation that includes both --data '{...}' and --file payload.json; scripts where a wrapper adds --data while the user also passes --file.

Common situations: Shell scripts accumulating flags across conditionals; copy-pasting an example command that already contains --data onto one that uses --file; CI templates with default data plus user-provided file.

Related errors


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