can1357/oh-my-pi · info

export requires --output <path>

Error message

export requires --output <path>

What it means

Even with a valid scan id and format, /security export needs a destination path via --output. exportResults() throws this error after option parsing when outputPath is still undefined. Without it the command would have nowhere to write the serialized bundle.

Source

Thrown at packages/coding-agent/src/slash-commands/helpers/security.ts:191

async function exportResults(runtime: SlashCommandRuntime, rest: string): Promise<void> {
	const tokens = parseCommandArgs(rest);
	const scanId = tokens[0];
	if (!scanId) throw new Error("export requires <scan-id> --output <path> [--format bundle|sarif|report]");
	let outputPath: string | undefined;
	let format: "bundle" | "sarif" | "report" = "bundle";
	for (let index = 1; index < tokens.length; index++) {
		const token = tokens[index]!;
		if (token === "--output") outputPath = requireToken(tokens, ++index, token);
		else if (token === "--format") {
			const value = requireToken(tokens, ++index, token);
			if (value !== "bundle" && value !== "sarif" && value !== "report") {
				throw new Error(`Unknown export format: ${value}`);
			}
			format = value;
		} else throw new Error(`Unknown export option: ${token}`);
	}
	if (!outputPath) throw new Error("export requires --output <path>");
	const store = await SecurityStore.openForCwd(runtime.cwd);
	const bundle = await store.getBundle(scanIdFromInput(scanId));
	if (!bundle) throw new Error(`Unknown security scan: ${scanId}`);
	let content: string;
	if (format === "sarif") {
		if (!bundle.sarif) throw new Error(`Security scan ${scanId} has no SARIF result`);
		content = `${JSON.stringify(bundle.sarif, null, 2)}\n`;
	} else if (format === "report") {
		if (bundle.report === undefined) throw new Error(`Security scan ${scanId} has no report`);
		content = bundle.report;
	} else {
		content = `${JSON.stringify(bundle, null, 2)}\n`;
	}
	const absolute = path.resolve(runtime.cwd, outputPath);
	await writeSecurityFileAtomic(absolute, content, { hardenParent: false });
	await runtime.output(`Exported security scan ${scanId} to ${shortenPath(absolute)}.`);
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Add --output <path>: /security export <scan-id> --output ./export.json
  2. Quote paths containing spaces: --output "./my exports/bundle.json"
  3. The path is resolved against runtime.cwd if relative

Example fix

// before
/security export scan-abc --format report
// after
/security export scan-abc --format report --output ./report.md
Defensive patterns

Strategy: validation

Validate before calling

function validateExportHasOutput(rest: string): boolean {
  const tokens = rest.trim().split(/\s+/).filter(Boolean);
  const i = tokens.indexOf("--output");
  return i !== -1 && typeof tokens[i + 1] === "string";
}
// require true before invoking /security export

Try / catch

try {
  await runSlashCommand(`/security export ${scanId} ${args}`);
} catch (err) {
  if (err instanceof Error && err.message === "export requires --output <path>") {
    // re-issue with an explicit --output path
  } else throw err;
}

Prevention

When it happens

Trigger: Running /security export <scan-id> with no --output flag; passing --format but forgetting --output; an automation strips the --output pair because of a quoting bug leaving the value consumed elsewhere.

Common situations: Developer expects output to stdout or a default filename (export always writes to an explicit path); a wrapper script drops arguments containing spaces that were not quoted; the user combined subcommand syntax from memory.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2a504d25edcdcbbe. Report an issue: GitHub.