Hmbown/CodeWhale · error · Error
Choose one input source, an unused --output path (or…
Error message
Choose one input source, an unused --output path (or --resume), and JSONL for live recording. Runtime requires --thread.
What it means
After syntax validation, pet.mjs enforces its input-source contract: --output is required; exactly one of --input, --demo, --runtime must be given; live modes (--watch or --runtime) require --format=jsonl; --watch requires --input; --runtime requires --thread (and vice versa); --trace requires --input; --segment-buckets requires live mode; --resume requires live mode. Any violation of these mutual constraints throws this combined-message error.
Solutions
- Pick exactly one source: either --input=<file>, or --demo, or --runtime=<url> with --thread=<id>.
- Always pass --output=<path> that doesn't already exist (unless resuming a live recording).
- Use --format=jsonl (the default) for --watch or --runtime recording; reserve tsv for file conversion.
- Drop --resume and --segment-buckets unless doing live recording; drop --trace unless converting an --input file.
- Run --help to see the full accepted usage line.
Example fix
// before node scripts/pet.mjs --runtime=http://127.0.0.1:7878 --output=pet.jsonl // after node scripts/pet.mjs --runtime=http://127.0.0.1:7878 --thread=abc123 --output=pet.jsonl
Defensive patterns
Strategy: validation
Validate before calling
function validatePetArgs(args) {
const opt = n => (args.find(a => a.startsWith(`--${n}=`)) ?? '').split('=')[1];
const has = f => args.includes(f);
const sources = [!!opt('input'), has('--demo'), !!opt('runtime')].filter(Boolean).length;
return opt('output') && sources === 1 && ['jsonl','tsv'].includes(opt('format') ?? 'jsonl') &&
(!opt('runtime') || !!opt('thread'));
}
if (!validatePetArgs(args)) console.error('pick one source + --output (+ --thread for --runtime)'); Try / catch
try {
await runPetCli(args);
} catch (err) {
if (err.message.startsWith('Choose one input source')) {
console.error('Usage: node scripts/pet.mjs --help'); process.exit(2);
}
throw err;
} Prevention
- Choose exactly one of --input, --demo, --runtime per invocation.
- Remember --runtime always pairs with --thread, and live modes require jsonl output.
- Only use --resume, --segment-buckets, and --watch in live-recording scenarios.
- Build command lines from the --help usage string, not ad hoc.
When it happens
Trigger: No --output path; combining two or three of --input/--demo/--runtime; --runtime without --thread (or --thread without --runtime); using --format=tsv with --watch or --runtime; --watch without --input; --trace without --input; --segment-buckets with a non-live source; --resume without live recording.
Common situations: Forgot --thread when pointing at a Runtime URL; tried TSV output for a live recording; combined --demo with --input while experimenting; added --resume to a one-shot file conversion.
Related errors
- --write-receipt and --check-receipt are mutually exclusive
- --days must be an integer from 1 through 90
- duration resolved to zero seconds
- invalid value ' ' for '--provider ': expected one of …
- --max-passes applies only to --pr reviews
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/d7148f9e42f641ff.
Report an issue: GitHub.
Appendix: source
Thrown at pet/scripts/pet.mjs:25
import { compilePetTelemetry, encodePetJSONL, encodePetTSV } from '../dist/core/pet-telemetry.js';
import { petDemoEvents } from '../dist/core/pet-demo.js';
import { followRuntime } from './lib/pet-runtime.mjs';
import { createPetRecorder } from './lib/pet-recorder.mjs';
const args = process.argv.slice(2);
const option = name => args.find(a => a.startsWith(`--${name}=`))?.slice(name.length + 3);
if (args.includes('--help')) {
console.log('node scripts/pet.mjs --input=trace.jsonl --output=pet.jsonl [--trace=ID] [--format=jsonl|tsv] [--watch]\nnode scripts/pet.mjs --runtime=http://127.0.0.1:7878 --thread=ID --output=pet.jsonl [--segment-buckets=216000] [--resume]\nUse --demo instead of --input for synthetic telemetry. Output must not already exist unless --resume is used for live recording. A resumed recorder preserves the previous segment and starts unknown at the same path.\nLive recording rotates at 216000 buckets or 64 MiB into OUTPUT.segment-NNNNNN.jsonl and continues at the same live path. All archives are retained.\nRuntime reads only the existing local event journal. Optional authentication comes from CODEWHALE_RUNTIME_TOKEN; never put a token in the URL. No agent or provider is started.');
process.exit(0);
}
let output, recorder, monitor, timer, runtime;
try {
for (const a of args) if (!['--demo', '--watch', '--resume'].includes(a) && !/^--(input|output|trace|format|runtime|thread|segment-buckets)=.+/.test(a)) throw new Error('Unknown or empty option. Use --help.');
const input = option('input'), runtimeURL = option('runtime'), path = option('output'), format = option('format') ?? 'jsonl', live = args.includes('--watch') || !!runtimeURL;
if (!path || [!!input, args.includes('--demo'), !!runtimeURL].filter(Boolean).length !== 1
|| !['jsonl', 'tsv'].includes(format) || live && format !== 'jsonl' || args.includes('--watch') && !input
|| !!runtimeURL !== !!option('thread') || option('trace') && !input || option('segment-buckets') && !live || args.includes('--resume') && !live)
throw new Error('Choose one input source, an unused --output path (or --resume), and JSONL for live recording. Runtime requires --thread.');
const load = async () => {
if (!input) return { events: petDemoEvents(), duration: 80_000 };
if ((await stat(input)).size > 64 * 1024 * 1024) throw new Error('Input exceeds 64 MiB.');
const traces = importTrace(await readFile(input, 'utf8'), input, { privacy: 'metadata' });
const trace = option('trace') ? traces.find(t => t.id === option('trace')) : traces.length === 1 ? traces[0] : undefined;
if (!trace) throw new Error('Select an existing --trace ID when input contains multiple traces.');
return trace;
};
let trace = runtimeURL ? undefined : await load(), buckets = compilePetTelemetry(trace?.events ?? [], trace?.duration ?? 0);
if (live) recorder = await createPetRecorder(path, { resume: args.includes('--resume'), maxBuckets: option('segment-buckets') === undefined ? 216_000 : Number(option('segment-buckets')), report: text => console.error(text) });
else output = await open(path, 'wx', 0o600);
if (runtimeURL) runtime = await followRuntime({ baseUrl: runtimeURL, threadId: option('thread'),
token: process.env.CODEWHALE_RUNTIME_TOKEN, report: text => console.error(text) });
if (!live) {
await output.writeFile(format === 'tsv' ? encodePetTSV(buckets) : encodePetJSONL(buckets));
await output.close(); output = undefined;
console.log(`Wrote ${buckets.length} pet buckets (${args.includes('--demo') ? 'demo' : 'trace replay'}).`);
} else {View on GitHub (pinned to 433685b202)