{"record":{"id":"8fa9ea1155477c43","repo":"Hmbown/CodeWhale","slug":"choose-one-recording-to-import","errorCode":null,"errorMessage":"Choose one recording to import.","messagePattern":"Choose one recording to import\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/ui/pet.ts","lineNumber":200,"sourceCode":"  interactions = []; seek.max = mode.value === 'demo' ? '80' : '120';\n  source.textContent = mode.value === 'demo' ? 'Event demo · synthetic telemetry' : 'Wild · simulated creature'; rebuild();\n  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.';\n};\nget<HTMLInputElement>('file').onchange = async event => {\n  const input = event.target as HTMLInputElement, file = input.files?.[0]; if (!file) return;\n  try {\n    if (file.size > 64 * 1024 * 1024) throw new Error('Pet import exceeds 64 MiB.');\n    const text = await file.text(); let replay: unknown;\n    try { replay = JSON.parse(text); } catch { /* JSONL and trace imports follow below. */ }\n    let next: PetWorld;\n    if (replay && typeof replay === 'object' && 'petReplayVersion' in replay) next = PetWorld.fromRecording(points, replay);\n    else {\n      let nextTape: readonly PetBucket[];\n      const first = replay ?? JSON.parse(text.split(/\\r?\\n/).find(line => line.trim()) || '{}');\n      if (first && typeof first === 'object' && 'version' in first && first.version === 1 && 'simTimeMs' in first) nextTape = decodePetJSONL(text);\n      else {\n        const traces = importTrace(text, file.name, { privacy: 'metadata' });\n        if (traces.length !== 1) throw new Error('Choose one recording to import.');\n        nextTape = compilePetTelemetry(traces[0].events, traces[0].duration);\n      }\n      next = new PetWorld(points, nextTape, [], 2, true);\n    }\n    if (!await mayLeave()) return;\n    adoptImported(next, `Local replay · ${file.name}`);\n    message.textContent = 'Recording loaded locally, including its current pose, interactions and score.';\n  } catch (error) { message.textContent = error instanceof Error ? error.message : 'Unable to import this file.'; }\n  finally { input.value = ''; }\n};\nget('save').onclick = () => {\n  try {\n    const chunks: string[] = []; let bytes = 0;\n    for (let index = 0; ; index++) {\n      const chunk = world.recordingChunk(index); if (chunk === null) break;\n      bytes += new TextEncoder().encode(chunk).length;\n      if (bytes > 64 * 1024 * 1024) throw new Error('Recording exceeds the 64 MiB export limit. The current world was kept.');\n      chunks.push(chunk);","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/ui/pet.ts#L182-L218","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`."],"exampleFix":"// before: importing a combined multi-trace export\nthrow new Error('Choose one recording to import.');\n// after: filter to a single trace client-side first\nconst traces = importTrace(text, file.name, { privacy: 'metadata' });\nif (traces.length !== 1) { /* pick traces[0] explicitly or re-export a single recording */ }","handlingStrategy":"validation","validationCode":"const traces = importTrace(text, file.name, { privacy: 'metadata' });\nif (traces.length !== 1) { alert('Please choose a file containing exactly one recording.'); return; }","typeGuard":"const isSingleTrace = (t: { length: number }) => t.length === 1;","tryCatchPattern":"try { /* import */ } catch (e) { if (e.message.includes('Choose one recording')) showMessage('Select a single-recording file.'); }","preventionTips":["Export exactly one recording per file for import.","Check file contents count before invoking the importer.","Prefer the JSONL tape format for automated imports."],"tags":["import","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}