{"record":{"id":"d1d7b4cfe2483947","repo":"plandex-ai/plandex","slug":"error-writing-file-v-d1d7b4","errorCode":null,"errorMessage":"error writing file: %v","messagePattern":"error writing file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/diff_helpers.go","lineNumber":72,"sourceCode":"\t\t\t\t\tlog.Printf(\"panic in GetPlanDiffs: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"panic in GetPlanDiffs: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel\n\t\t\t\t}\n\t\t\t}()\n\t\t\t_, hasPath := files[path]\n\t\t\t_, hasRemoved := removed[path]\n\t\t\tif hasPath || hasRemoved {\n\t\t\t\thasAnyOriginal = true\n\t\t\t\t// ensure file directory exists\n\t\t\t\terr = os.MkdirAll(filepath.Dir(filepath.Join(tempDirPath, path)), 0755)\n\t\t\t\tif err != nil {\n\t\t\t\t\terrCh <- fmt.Errorf(\"error creating directory: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\terr = os.WriteFile(filepath.Join(tempDirPath, path), []byte(context.Body), 0644)\n\t\t\t\tif err != nil {\n\t\t\t\t\terrCh <- fmt.Errorf(\"error writing file: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\terrCh <- nil\n\t\t}(path, context)\n\t}\n\n\tfor range planState.ContextsByPath {\n\t\terr = <-errCh\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error writing original files to temp dir: %v\", err)\n\t\t}\n\t}\n\n\tif hasAnyOriginal {\n\t\t// add and commit the files in the temp dir\n\t\terr := gitAdd(tempDirPath, \".\")\n\t\tif err != nil {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/diff_helpers.go#L54-L90","documentation":"After the directory exists, the goroutine writes the original file body (context.Body) into the temp repo with os.WriteFile. A failure here (permissions, ENOSPC, invalid path, temp dir removed) is sent on errCh and later wrapped by GetPlanDiffs as 'error writing original files to temp dir: error writing file: ...'.","triggerScenarios":"os.WriteFile(filepath.Join(tempDirPath, path), []byte(context.Body), 0644) fails: disk full, permissions, path too long, or temp dir deleted mid-run.","commonSituations":"Very large file bodies exceeding quota/disk; read-only mounts; tmp cleaner racing the goroutines; filenames from plan state that the local filesystem cannot represent.","solutions":["Read the wrapped os error to identify ENOSPC/EACCES/ENAMETOOLONG and address that specific cause.","Free disk space or increase quota for the org/tmp volume.","Verify temp dir exists and is writable for the whole GetPlanDiffs run; stop concurrent cleanup jobs.","Validate/sanitize the file path before writing (no NUL, no '..')."],"exampleFix":"// before\nerr = os.WriteFile(filepath.Join(tempDirPath, path), []byte(context.Body), 0644)\n// after\nif err := os.WriteFile(filepath.Join(tempDirPath, path), []byte(context.Body), 0644); err != nil {\n    errCh <- fmt.Errorf(\"error writing file %s: %v\", path, err)\n    return\n}","handlingStrategy":"validation","validationCode":"if len(context.Body) > maxFileBodyBytes {\n    return fmt.Errorf(\"file body for %s exceeds %d bytes\", path, maxFileBodyBytes)\n}\nif err := hasFreeSpace(tempDirPath, uint64(len(context.Body))); err != nil {\n    return err\n}","typeGuard":null,"tryCatchPattern":"out, err := GetPlanDiffs(orgId, planId, plain)\nvar pathErr *os.PathError\nif err != nil && errors.As(err, &pathErr) {\n    log.Printf(\"filesystem failure on %s: %v\", pathErr.Path, pathErr.Err)\n    // ENOSPC -> free space; EACCES -> fix permissions\n}","preventionTips":["Alert on disk usage thresholds for the volume backing org/temp storage.","Validate plan file paths and sizes before writing.","Prevent concurrent cleanup of the temp dir while GetPlanDiffs runs.","Run the server under a user with write access to the entire temp tree."],"tags":["filesystem","io","disk"],"backgroundTag":"file-write-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}