Hmbown/CodeWhale · error · Error
Choose one recording to import.
Error message
Choose one recording to import.
What it means
Thrown during PET replay import when the selected file is parsed as a trace recording and `importTrace` returns a number of traces other than exactly one. The import path supports JSONL replay tapes and single-recording trace exports; a file containing zero or multiple recordings is ambiguous and the library refuses to guess.
Solutions
- Export a single recording from the trace tool and re-import that file.
- Verify the file is non-empty and contains exactly one trace recording.
- If importing a replay, use the JSONL tape format with a version-1 header containing `simTimeMs`.
Example fix
// before: importing a combined multi-trace export
throw new Error('Choose one recording to import.');
// after: filter to a single trace client-side first
const traces = importTrace(text, file.name, { privacy: 'metadata' });
if (traces.length !== 1) { /* pick traces[0] explicitly or re-export a single recording */ } Defensive patterns
Strategy: validation
Validate before calling
const traces = importTrace(text, file.name, { privacy: 'metadata' });
if (traces.length !== 1) { alert('Please choose a file containing exactly one recording.'); return; } Type guard
const isSingleTrace = (t: { length: number }) => t.length === 1; Try / catch
try { /* import */ } catch (e) { if (e.message.includes('Choose one recording')) showMessage('Select a single-recording file.'); } Prevention
- Export exactly one recording per file for import.
- Check file contents count before invoking the importer.
- Prefer the JSONL tape format for automated imports.
When it happens
Trigger: Calling the import handler (file picker `onchange`) with a text file that is not a version-1 JSONL tape (`simTimeMs` header missing) and whose contents `importTrace(text, file.name, { privacy: 'metadata' })` yields an array of length != 1.
Common situations: User picks a multi-recording combined export, an empty or truncated trace file, or an unrelated JSON/text file that is not a pet replay.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- bundle contains conflicting or rejected entries
- Codewhale runtime event file is empty.
- Duplicate producer incarnation/sequence in evidence bundle…
- import source must be a compatible external skill
- Invalid MCP entry; contents omitted
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/8fa9ea1155477c43.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/ui/pet.ts:200
interactions = []; seek.max = mode.value === 'demo' ? '80' : '120';
source.textContent = mode.value === 'demo' ? 'Event demo · synthetic telemetry' : 'Wild · simulated creature'; rebuild();
message.textContent = mode.value === 'demo' ? 'Synthetic event-v1 telemetry uses the same derivation as imported traces.' : 'Wild mode is a simulated creature. Import event-v1, OTLP, or Codewhale telemetry to see work.';
};
get<HTMLInputElement>('file').onchange = async event => {
const input = event.target as HTMLInputElement, file = input.files?.[0]; if (!file) return;
try {
if (file.size > 64 * 1024 * 1024) throw new Error('Pet import exceeds 64 MiB.');
const text = await file.text(); let replay: unknown;
try { replay = JSON.parse(text); } catch { /* JSONL and trace imports follow below. */ }
let next: PetWorld;
if (replay && typeof replay === 'object' && 'petReplayVersion' in replay) next = PetWorld.fromRecording(points, replay);
else {
let nextTape: readonly PetBucket[];
const first = replay ?? JSON.parse(text.split(/\r?\n/).find(line => line.trim()) || '{}');
if (first && typeof first === 'object' && 'version' in first && first.version === 1 && 'simTimeMs' in first) nextTape = decodePetJSONL(text);
else {
const traces = importTrace(text, file.name, { privacy: 'metadata' });
if (traces.length !== 1) throw new Error('Choose one recording to import.');
nextTape = compilePetTelemetry(traces[0].events, traces[0].duration);
}
next = new PetWorld(points, nextTape, [], 2, true);
}
if (!await mayLeave()) return;
adoptImported(next, `Local replay · ${file.name}`);
message.textContent = 'Recording loaded locally, including its current pose, interactions and score.';
} catch (error) { message.textContent = error instanceof Error ? error.message : 'Unable to import this file.'; }
finally { input.value = ''; }
};
get('save').onclick = () => {
try {
const chunks: string[] = []; let bytes = 0;
for (let index = 0; ; index++) {
const chunk = world.recordingChunk(index); if (chunk === null) break;
bytes += new TextEncoder().encode(chunk).length;
if (bytes > 64 * 1024 * 1024) throw new Error('Recording exceeds the 64 MiB export limit. The current world was kept.');
chunks.push(chunk);View on GitHub (pinned to 433685b202)