{"record":{"id":"2f2ea7d7ee4f393c","repo":"can1357/oh-my-pi","slug":"short-write","errorCode":null,"errorMessage":"Short write","messagePattern":"Short write","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-storage.ts","lineNumber":138,"sourceCode":"\t\twriterRegistry.register(this, this.#fd, this);\n\t}\n\n\t#recordError(err: unknown): Error {\n\t\tconst error = toError(err);\n\t\tif (!this.#error) this.#error = error;\n\t\tthis.#onError?.(error);\n\t\treturn error;\n\t}\n\n\t#writeNow(line: string): void {\n\t\tconst originalSize = fs.fstatSync(this.#fd).size;\n\t\tconst buf = Buffer.from(line, \"utf-8\");\n\t\tlet offset = 0;\n\t\ttry {\n\t\t\twhile (offset < buf.length) {\n\t\t\t\tconst written = fs.writeSync(this.#fd, buf, offset, buf.length - offset);\n\t\t\t\tif (written === 0) {\n\t\t\t\t\tthrow new Error(\"Short write\");\n\t\t\t\t}\n\t\t\t\toffset += written;\n\t\t\t}\n\t\t} catch (writeError) {\n\t\t\ttry {\n\t\t\t\tfs.ftruncateSync(this.#fd, originalSize);\n\t\t\t} catch (rollbackError) {\n\t\t\t\tthrow new AggregateError(\n\t\t\t\t\t[toError(writeError), toError(rollbackError)],\n\t\t\t\t\t\"Session append failed and its partial bytes could not be rolled back\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow writeError;\n\t\t}\n\t}\n\n\tappendSync(line: string): void {\n\t\tif (this.#closed) throw new Error(\"Writer closed\");","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-storage.ts#L120-L156","documentation":"SessionStorage appendSync writes each JSONL line with a loop of fs.writeSync calls. If a writeSync call reports 0 bytes written, progress would stall forever (the loop would never advance), so the code throws this Error, truncates the file back to its original size, and rethrows. It signals the OS/file descriptor accepted the write request but wrote nothing — a rare low-level I/O failure.","triggerScenarios":"writeSync on the session file descriptor returning 0: typically a full disk returning ENOSPC-adjacent behavior, a file descriptor that became invalid/closed, hitting a filesystem quota, or I/O errors on the underlying storage device.","commonSituations":"Disk-full or quota-exhausted volumes while a long agent session is appending; network/external drives dropping; containerized environments with a full tmpfs holding the session directory.","solutions":["Free disk space on the volume holding the session directory (~/.omp or the configured session path) and retry the operation.","Check the filesystem quota for the user; raise it or clear space.","Verify the disk isn't failing: check dmesg / SMART errors if writeSync returns 0 repeatedly.","Restart the CLI so a fresh SessionStorage (and valid fd) is created; the failed append was rolled back via ftruncate so the session file is intact up to the previous line."],"exampleFix":"// no code fix; environment remedy\n// check space before relying on appends:\ndf -h ~/.omp\n// after freeing space, retry the session write (file was rolled back to original size).","handlingStrategy":"retry","validationCode":"import { statfs } from \"node:fs/promises\";\nconst s = await statfs(sessionDir);\nif (s.bavail * s.bsize < 50 * 1024 * 1024) {\n  throw new Error(`Low disk space on ${sessionDir}; appendSync may fail`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  storage.appendSync(line);\n} catch (err) {\n  if (err.message === \"Short write\") {\n    logger.error(\"Session append wrote 0 bytes — check disk space/fd health\", { err });\n    // file was truncated back to original size; safe to retry after remediation\n  } else throw err;\n}","preventionTips":["Monitor free disk space on the volume holding session files.","Avoid placing the session directory on network/quota-limited mounts.","Restart the app if a file descriptor may have gone stale.","Alert on disk-full conditions before writes start failing."],"tags":["filesystem","io","disk-full","session"],"backgroundTag":"short-write","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}