n8n-io/n8n · error · Error

Unexpected positional argument

Error message

Unexpected positional argument

What it means

Thrown by the default case of parseRawArgs() (args.ts:512) when an argument does not start with -- and is not consumed as a flag value. Unlike build-mcp-manifest.ts (which accepts positional slug arguments), this eval CLI parser does not accept any positional arguments — all configuration must come through flags. The error is thrown without echoing the positional value, because raw CLI input may contain secrets (e.g. an accidentally pasted token).

Source

Thrown at packages/@n8n/instance-ai/evaluations/cli/args.ts:512

				i++;
				break;

			case '--build-timeout-ms':
				result.buildTimeoutMs = parseIntArg(argv, i, '--build-timeout-ms');
				result.buildOnlyFlags.push(arg);
				i++;
				break;

			default:
				// Fail loudly on unknown flags. Strip any =value payload before
				// echoing and drop positional values entirely — raw CLI input
				// may contain secrets (e.g. --password=... or an accidentally
				// pasted token) that would otherwise leak into terminal/CI logs.
				if (arg.startsWith('--')) {
					const flagName = arg.split('=', 1)[0];
					throw new Error(`Unknown flag: ${flagName}`);
				}
				throw new Error('Unexpected positional argument');
		}
	}

	return result;
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function nextArg(argv: string[], currentIndex: number, flagName: string): string {
	const value = argv[currentIndex + 1];
	if (value === undefined || value.startsWith('--')) {
		throw new Error(`Missing value for ${flagName}`);
	}
	return value;
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Convert the positional into the appropriate flag form: test-case substrings go to --filter, file paths go to --prebuilt-workflows or --output-dir.
  2. Remove the positional argument if it was unintended.
  3. Review the parseRawArgs switch cases to find the correct flag for your intent.

Example fix

// before
pnpm eval:instance-ai contact-form --base-url http://localhost:5678
// after
pnpm eval:instance-ai --filter contact-form --base-url http://localhost:5678
Defensive patterns

Strategy: validation

Validate before calling

function assertNoPositionals(args: string[]): void {
  for (let i = 0; i < args.length; i++) {
    const a = args[i];
    if (!a.startsWith('--')) {
      // It's a positional only if the previous flag didn't consume it as a value.
      const prev = args[i - 1];
      const valueFlags = new Set(['--timeout-ms','--base-url','--email','--password','--filter','--exclude','--prebuilt-workflows','--output-dir','--iterations','--dataset','--concurrency','--experiment-name','--pin-ai-roots','--tier','--baseline-prefix','--source','--suite','--mcp-server','--build-cwd','--build-max-attempts','--build-mcp-timeout-ms','--build-timeout-ms']);
      if (!prev || !valueFlags.has(prev.split('=',1)[0])) {
        throw new Error(`Unexpected positional argument: ${a}`);
      }
    }
  }
}

Prevention

When it happens

Trigger: Passing a bare positional argument to the eval CLI, e.g. `pnpm eval:instance-ai some-slug` or `pnpm eval:instance-ai ./path`. Any token that is not a --flag and is not the value of a preceding flag triggers it.

Common situations: A developer confuses this CLI with build-mcp-manifest (which accepts positional slugs), or passes a test-case filter as a positional instead of via --filter. Also triggered by a shell glob expanding into a bare token.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/32eb0a0870eed954. Report an issue: GitHub.