{"record":{"id":"1b36098f05a3d98e","repo":"gastownhall/beads","slug":"failed-to-close-interactions-log-w","errorCode":null,"errorMessage":"failed to close interactions log: %w","messagePattern":"failed to close interactions log: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/audit/audit.go","lineNumber":98,"sourceCode":"\t}\n}\n\n// EnsureFile creates .beads/interactions.jsonl if it does not exist.\nfunc EnsureFile() (string, error) {\n\tp, err := Path()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif err := os.MkdirAll(filepath.Dir(p), 0700); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create .beads directory: %w\", err)\n\t}\n\tif ensureFileBeforeCreateHook != nil {\n\t\tensureFileBeforeCreateHook(p)\n\t}\n\tf, err := os.OpenFile(p, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) // nolint:gosec // JSONL is intended to be shared via git across clones/tools.\n\tif err == nil {\n\t\tif closeErr := f.Close(); closeErr != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to close interactions log: %w\", closeErr)\n\t\t}\n\t\treturn p, nil\n\t}\n\tif !errors.Is(err, os.ErrExist) {\n\t\treturn \"\", fmt.Errorf(\"failed to create interactions log: %w\", err)\n\t}\n\treturn p, nil\n}\n\n// Append appends an event to .beads/interactions.jsonl as a single JSON line.\n// This is intentionally append-only: callers must not mutate existing lines.\nfunc Append(e *Entry) (string, error) {\n\tif e == nil {\n\t\treturn \"\", fmt.Errorf(\"nil entry\")\n\t}\n\tif e.Kind == \"\" {\n\t\treturn \"\", fmt.Errorf(\"kind is required\")\n\t}","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/audit/audit.go#L80-L116","documentation":"When the interactions log does not yet exist, EnsureFile creates it with O_CREATE|O_EXCL and immediately closes it to reserve the file. If that immediate Close returns an error, it is wrapped with 'failed to close interactions log'. This is rare and usually signals an underlying I/O problem rather than a logic issue.","triggerScenarios":"Creating the audit JSONL file for the first time (no other writer won the O_EXCL race) and the subsequent f.Close() fails due to delayed I/O errors or fd/table exhaustion.","commonSituations":"Full disks or failing storage surfacing errors at close, containers with low fd limits, or unusual filesystems that report errors on close.","solutions":["Check disk space and filesystem health (dmesg, fsck)","Raise the process file-descriptor limit (ulimit -n) if fd exhaustion is implicated","Retry the operation; if it persists, move the .beads directory to healthy storage"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"p, err := audit.EnsureFile()\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to close interactions log\") {\n        log.Printf(\"transient I/O problem creating audit log: %v\", err)\n        return retryEnsure()\n    }\n    return err\n}","preventionTips":["Monitor fd limits and disk health on hosts running bd","Retry EnsureFile once on transient close errors","Treat repeated failures as a storage-health signal, not a bd bug"],"tags":["filesystem","io","beads"],"backgroundTag":"file-close-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}