n8n-io/n8n · error · Error

Pass --results <eval-results.json> (repeatable, one per arm)

Error message

Pass --results <eval-results.json> (repeatable, one per arm) or --probe-thread <id>.

What it means

Thrown by main() in build-cost-report.ts:448 when neither --results nor --probe-thread is provided. The tool has two modes: a multi-arm cost comparison (one or more --results files) or a single-thread connectivity spot-check (--probe-thread <id>). With neither, there is nothing to do, so the parser fails fast with usage guidance.

Source

Thrown at packages/@n8n/instance-ai/evaluations/cli/build-cost-report.ts:448

	const probeThread = single(flags, 'probe-thread');
	if (probeThread) {
		const ls = await langsmithConfig();
		const projectId = await resolveTraceProjectId(ls, traceProject);
		const cost = await sumThreadCost(ls, projectId, probeThread);
		if (!cost) {
			console.log(`thread ${probeThread}: no runs found in trace project "${traceProject}"`);
			return;
		}
		console.log(
			`thread ${probeThread}: ${cost.turns} turns, ${cost.tokens.toLocaleString()} tokens, ${fmtUsd(cost.costUsd)}`,
		);
		return;
	}

	const resultPaths = flags.get('results') ?? [];
	const labels = flags.get('label') ?? [];
	if (resultPaths.length === 0) {
		throw new Error(
			'Pass --results <eval-results.json> (repeatable, one per arm) or --probe-thread <id>.',
		);
	}

	// LangSmith access is resolved once, lazily — only when some arm needs the
	// thread join (a persisted-spend-only comparison runs without credentials).
	let ls: LangSmithConfig | undefined;
	let projectId: string | undefined;

	const arms: ArmSummary[] = [];
	for (let i = 0; i < resultPaths.length; i++) {
		const results = loadResults(resultPaths[i]);
		const label = labels[i] ?? results.experimentName ?? `arm${String(i + 1)}`;
		const hasPersistedSpend = results.testCases.some((tc) => tc.buildCostUsdPerRun !== undefined);
		const hasThreads = results.testCases.some((tc) =>
			(tc.threadIds ?? []).some((id) => id !== null),
		);
		if (hasPersistedSpend) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Pass at least one --results <eval-results.json> for a cost comparison report (repeatable, one per arm).
  2. Or pass --probe-thread <thread-id> for a single-thread cost spot-check.
  3. Verify any shell variables expanding into --results paths are non-empty: `echo "${RESULTS:?unset}".

Example fix

// before
pnpm tsx evaluations/cli/build-cost-report.ts
// after
pnpm tsx evaluations/cli/build-cost-report.ts --results mcp-run/eval-results.json --results aia-run/eval-results.json --label mcp --label aia
Defensive patterns

Strategy: validation

Validate before calling

function validateReportInputs(args: string[]): void {
  const hasResults = args.includes('--results');
  const hasProbe = args.includes('--probe-thread');
  if (!hasResults && !hasProbe) {
    throw new Error('Pass --results <file> or --probe-thread <id>');
  }
}

Prevention

When it happens

Trigger: Invoking build-cost-report.ts with no arguments, or with only non-input flags (e.g. only --trace-project or --out but no --results and no --probe-thread).

Common situations: A developer runs the script expecting a default behavior, or an argument was lost during command construction. Also occurs when --results paths are all behind a shell expansion that produced nothing.

Related errors


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