{"record":{"id":"d32fe3004b728bb1","repo":"shadow1ng/fscan","slug":"failed-to-write-realtime-backup-w","errorCode":null,"errorMessage":"failed to write realtime backup: %w","messagePattern":"failed to write realtime backup: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/output/writers.go","lineNumber":137,"sourceCode":"func (w *TXTWriter) Write(result *ScanResult) error {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\tif w.closed {\n\t\treturn fmt.Errorf(\"writer is closed\")\n\t}\n\tif result == nil {\n\t\treturn fmt.Errorf(\"result cannot be nil\")\n\t}\n\n\t// 1. 加入内存分类缓冲（用于最终有序输出）\n\tw.buffer.Add(result)\n\n\t// 2. 实时写入备份文件（防崩溃丢数据）\n\tif w.realtimeFile != nil {\n\t\tline := w.formatLine(result)\n\t\tif _, err := w.realtimeFile.WriteString(line + \"\\n\"); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write realtime backup: %w\", err)\n\t\t}\n\t\tif err := w.realtimeFile.Sync(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to sync realtime backup: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// getSeparator 获取分隔线文本\nfunc (w *TXTWriter) getSeparator(newType ResultType) string {\n\tswitch newType {\n\tcase TypeHost:\n\t\treturn i18n.GetText(\"output_section_hosts\")\n\tcase TypePort:\n\t\treturn i18n.GetText(\"output_section_ports\")\n\tcase TypeService:\n\t\treturn i18n.GetText(\"output_section_services\")","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/common/output/writers.go#L119-L155","documentation":"This error is returned by JSON-less (text) writers when writing a formatted line to the realtime backup file (.realtime.tmp) fails. The library keeps a realtime crash-safety backup of every scan result, so any disk write failure is surfaced immediately instead of being silently buffered. It wraps the underlying OS error via %w.","triggerScenarios":"Calling Write() on a writer whose realtimeFile is non-nil and whose underlying WriteString fails: disk full, file descriptor closed/invalid, permission revoked mid-run, or I/O error on the backing device.","commonSituations":"Disk quota exceeded during long scans; the .realtime.tmp file deleted or its directory removed while the process runs; running out of file descriptors after opening many writers; read-only filesystem remount.","solutions":["Check disk space (df -h) and free space on the output volume","Verify the output directory still exists and the process has write permission for the .realtime.tmp file","Inspect the wrapped error (%w / errors.Unwrap) for the exact OS-level cause (ENOSPC, EBADF, EACCES)","Reopen or recreate the writer pointing to a valid writable path","If backup durability is not required, use a writer variant without realtime backup"],"exampleFix":"// before\nif _, err := w.realtimeFile.WriteString(line + \"\\n\"); err != nil {\n\treturn fmt.Errorf(\"failed to write realtime backup: %w\", err)\n}\n// after\nif _, err := w.realtimeFile.WriteString(line + \"\\n\"); err != nil {\n\tif errors.Is(err, syscall.ENOSPC) {\n\t\tw.disableRealtimeBackup() // fall back to memory-only buffering\n\t} else {\n\t\treturn fmt.Errorf(\"failed to write realtime backup: %w\", err)\n\t}\n}","handlingStrategy":"try-catch","validationCode":"info, err := os.Stat(outDir)\nif err != nil || !info.IsDir() { return fmt.Errorf(\"output dir missing\") }\nif unix.Access(outDir, unix.W_OK) != nil { return fmt.Errorf(\"output dir not writable\") }\nusable := syscall.Statfs_t{}\nsyscall.Statfs(outDir, &usable)\nif usable.Bavail*uint64(usable.Bsize) < 64<<20 { return fmt.Errorf(\"low disk space\") }","typeGuard":null,"tryCatchPattern":"if err := writer.Write(result); err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOSPC) {\n\t\t// switch output volume or abort\n\t}\n\treturn fmt.Errorf(\"backup write failed: %w\", err)\n}","preventionTips":["Monitor free disk space before and during scans","Keep the output directory stable for the writer's lifetime","Avoid writing to network filesystems for realtime backups","Close writers exactly once, after all writes complete","Check ulimit -n when opening many writers concurrently"],"tags":["go","file-io","disk-write"],"backgroundTag":"file-write-failed","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}