{"record":{"id":"12b4839752d2fec9","repo":"gastownhall/beads","slug":"server-doltserver-stop-remove-pidfile-w","errorCode":null,"errorMessage":"server: DoltServer.Stop: remove pidfile: %w","messagePattern":"server: DoltServer\\.Stop: remove pidfile: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/storage/dbproxy/server/doltserver.go","lineNumber":382,"sourceCode":"\t}\n\tif waitErr != nil {\n\t\twaitErr = fmt.Errorf(\"server: DoltServer.Stop: %w\", waitErr)\n\t}\n\tvar closeErr error\n\tif s.logFile != nil {\n\t\tcloseErr = s.logFile.Close()\n\t\ts.logFile = nil\n\t}\n\tif closeErr != nil {\n\t\tcloseErr = fmt.Errorf(\"server: DoltServer.Stop: close log: %w\", closeErr)\n\t}\n\tvar rmErr error\n\tif s.pid != 0 {\n\t\trmErr = pidfile.Remove(s.rootDir, PIDFileName)\n\t\ts.pid = 0\n\t}\n\tif rmErr != nil {\n\t\trmErr = fmt.Errorf(\"server: DoltServer.Stop: remove pidfile: %w\", rmErr)\n\t}\n\treturn errors.Join(gcErr, waitErr, closeErr, rmErr)\n}\n\nfunc (s *DoltServer) runShutdownGC(ctx context.Context) (retErr error) {\n\tif s.database == \"\" || !s.Running(ctx) {\n\t\treturn nil\n\t}\n\tdb, err := sql.Open(\"mysql\", s.DSN(ctx, s.database, \"root\", \"\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open gc connection: %w\", err)\n\t}\n\tdefer func() { retErr = errors.Join(retErr, db.Close()) }()\n\n\tconn, err := db.Conn(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquire gc connection: %w\", err)\n\t}","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/server/doltserver.go#L364-L400","documentation":"DoltServer.Stop aggregates all shutdown errors via errors.Join, and this one wraps any failure from pidfile.Remove, which deletes the server's PID file from the root directory after the process has stopped. It means the server process itself shut down, but the bookkeeping file recording its PID could not be removed from disk.","triggerScenarios":"Calling DoltServer.Stop (via stopWithTimeout) when s.pid != 0 and pidfile.Remove fails to unlink <rootDir>/PIDFileName — e.g. permissions changed on the root dir, the directory was deleted concurrently, or the filesystem is read-only.","commonSituations":"Running the server as one user and stopping it as another (PID file owned by the original user); root directory mounted read-only at shutdown; container filesystem teardown racing Stop; antivirus/indexers briefly locking the file on network volumes.","solutions":["Check permissions/ownership of the server root directory and the PID file; ensure the stopping process can write there","Verify the root directory still exists and is writable before calling Stop","If the error is benign (stale pidfile in a tmpfs), remove the PID file manually and retry Stop","Do not treat this as a server failure: GC/wait/close errors in the joined error are the ones that matter for data integrity"],"exampleFix":"// before\nif err := server.Stop(ctx); err != nil { return err }\n// after\nif err := server.Stop(ctx); err != nil {\n    if !strings.Contains(err.Error(), \"remove pidfile\") {\n        return err // real shutdown problem\n    }\n    log.Warn(\"server stopped but pidfile removal failed; cleaning up\")\n    os.Remove(filepath.Join(rootDir, PIDFileName))\n}","handlingStrategy":"try-catch","validationCode":"// before Stop\nif info, err := os.Stat(rootDir); err != nil || !info.IsDir() {\n    return fmt.Errorf(\"server root %s missing or not a directory\", rootDir)\n}\nif err := unix.Access(rootDir, unix.W_OK); err != nil {\n    return fmt.Errorf(\"server root %s not writable: %w\", rootDir, err)\n}","typeGuard":"func isPidfileErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"remove pidfile\")\n}","tryCatchPattern":"if err := server.Stop(ctx); err != nil {\n    if isPidfileErr(err) {\n        log.Warn(\"non-fatal pidfile cleanup failure\", \"err\", err)\n    } else {\n        return err\n    }\n}","preventionTips":["Run Start and Stop under the same user account","Keep the server root directory writable by the service user","Exclude the data dir from read-only mounts and aggressive cleanup jobs","Treat pidfile errors in Stop as warnings; inspect the joined error for GC/close failures instead"],"tags":["go","filesystem","pidfile","shutdown"],"backgroundTag":"pidfile-removal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}