Hmbown/CodeWhale · error · Error

Wait for the pet recorder write before closing.

Error message

Wait for the pet recorder write before closing.

What it means

close() refuses to run while an append is still in flight (busy flag set). This protects the final fsync/close sequence from interleaving with an active write that still needs the output handle and lock.

Solutions

  1. Track in-flight appends and await them (e.g. Promise.all of pending appends) before calling close().
  2. Move close() after the producer loop fully drains.
  3. Use an async mutex/queue so close() waits behind pending writes.
  4. If close() is called by a signal handler, set a flag, drain writes, then close.

Example fix

// before
await recorder.append(last);
close(); // sync, races in-flight writes
// after
await recorder.append(last);
await recorder.close();
Defensive patterns

Strategy: try-catch

Validate before calling

if (pendingAppends.size > 0) throw new Error('cannot close: appends still in flight');

Try / catch

try {
  await Promise.all([...pendingAppends]);
  await recorder.close();
} catch (e) {
  if (e.message.includes('Wait for the pet recorder write')) {
    await Promise.allSettled([...pendingAppends]);
    await recorder.close();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling close() without awaiting a pending append() promise; a shutdown handler closing the recorder while a write/rotation is mid-flight; a timeout path calling close() concurrently with a slow rotation.

Common situations: SIGTERM handlers that close the recorder synchronously while a queued append is running; forgetting to await append in a batch loop; finally-block ordering that closes before draining writes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/b69ef0a26544652c. Report an issue: GitHub.

Appendix: source

Thrown at pet/scripts/lib/pet-recorder.mjs:166

            if (reopened.dev !== nextIdentity.dev || reopened.ino !== nextIdentity.ino)
              throw new Error('The live pet recording was replaced externally after rotation.');
            expectedMtime = reopened.mtimeNs;
            await syncDirectory(dirname(path));
            report(`Archived pet recording: ${archive}`);
          } finally {
            await next?.close();
            if (created && !installed) await unlink(temporary);
          }
          return;
        } else {
          await output.writeFile(row);
          expectedMtime = (await output.stat({ bigint: true })).mtimeNs;
        }
        bytes += size; sequence++;
      } finally { busy = false; }
    },
    async close() {
      if (busy) throw new Error('Wait for the pet recorder write before closing.');
      const current = output, heldLock = lock; output = undefined; lock = undefined;
      try { if (current) { try { await current.sync(); } finally { await current.close(); } } }
      finally { heldLock?.close(); }
    },
  };
}

View on GitHub (pinned to 433685b202)