affaan-m/ECC · error · CapsuleError
capsule.write_failed
capsule.write_failed
Error message
journal write made no progress
What it means
append() writes the canonical JSON entry to the journal with a manual write loop and throws 'capsule.write_failed' if a single fs.writeSync call reports zero or negative bytes written, meaning no forward progress is possible. This guards against infinite loops and silent data loss; the entry was already hashed but is NOT durably recorded, leaving the capsule in a pre-append state for the next verified read.
Solutions
- Check free disk space and quotas on the volume holding the capsule directory (df -h, quota).
- Retry the append after freeing space; the failed entry was not committed so re-appending is safe.
- Check filesystem/dmesg logs for I/O errors on the underlying device.
- Move the capsule directory to a local, non-quota-limited filesystem if using network mounts.
Example fix
// before: appending with <1MB free on a tiny tmpfs
await capsule.append('fix', 'note', { msg: 'x' }); // capsule.write_failed
// after: pre-check capacity and surface a clear message
const stat = fs.statfsSync(path.dirname(capsule.journalPath));
if (stat.bavail * stat.bsize < 1024 * 1024) {
throw new Error('insufficient disk space for capsule journal write');
}
await capsule.append('fix', 'note', { msg: 'x' }); Defensive patterns
Strategy: retry
Validate before calling
const dir = path.dirname(capsule.journalPath);
const st = fs.statfsSync(dir);
if (st.bavail * st.bsize < 5 * 1024 * 1024) throw new Error('low disk space before capsule append'); Try / catch
async function appendWithRetry(capsule, lineage, kind, payload, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await capsule.append(lineage, kind, payload);
} catch (e) {
const retryable = e instanceof CapsuleError && e.code === 'capsule.write_failed' && i < attempts - 1;
if (!retryable) throw e;
await new Promise(r => setTimeout(r, 2 ** i * 250));
}
}
} Prevention
- Monitor free space/quota on the volume hosting capsule directories.
- Run capsules on local disks rather than network filesystems.
- Keep journals small; archive and start new capsules per run.
- Alert on any capsule.write_failed — it usually indicates a system-level disk problem.
When it happens
Trigger: fs.writeSync returning <= 0 on the append-mode file descriptor — typically caused by disk-full conditions, EIO from failing storage, hitting a filesystem size limit/quota, or a closed/invalid descriptor in exotic environments.
Common situations: Disk quota exceeded on CI runners; tmpfs or container volume running out of space mid-run; network filesystems returning short/zero writes; the journal hitting a filesystem maximum file size.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Cannot read local asset
- stable source snapshot write made no progress
- all overlays must be readable local files
- all takes must be readable local files
- artifact byte count exceeded during reading
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f2d5e0e3ac0bbb13.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/eval-harness/capsule.js:219
ts: nowIso(this.clock),
lineage,
kind,
effect_class: effectClass,
harness_version: state.meta.harness_version,
task_family: state.meta.task_family,
parent_hash: state.root_hash,
payload: clean,
};
const entry = { ...body, entry_hash: envelope.computeEntryHash(body) };
const errors = envelope.validateEnvelope(entry);
if (errors.length > 0) throw new CapsuleError('capsule.invalid_entry', errors.join('; '));
const bytes = Buffer.from(canonicalJson(entry) + '\n', 'utf8');
const fd = fs.openSync(this.journalPath, 'a');
try {
let offset = 0;
while (offset < bytes.length) {
const written = fs.writeSync(fd, bytes, offset, bytes.length - offset, null);
if (written <= 0) throw new CapsuleError('capsule.write_failed', 'journal write made no progress');
offset += written;
}
fs.fsyncSync(fd);
} finally {
fs.closeSync(fd);
}
// These fields remain observable for compatibility, but are never used as
// authoritative append state. A preopened handle always reloads above.
this.meta = state.meta;
this.lastHash = entry.entry_hash;
this.nextSeq = entry.seq + 1;
return entry;
});
}
entries() {
const state = readJournal(this.journalPath);
if (!state.ok) {View on GitHub (pinned to 8321021c54)