{"record":{"id":"aa7f0d59a252f3aa","repo":"docker/compose","slug":"process-with-pid-d-is-still-running","errorCode":null,"errorMessage":"process with PID %d is still running","messagePattern":"process with PID (.+?) is still running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pidfile/pidfile.go","lineNumber":64,"sourceCode":"\tif pid != 0 && alive(pid) {\n\t\treturn pid, nil\n\t}\n\treturn 0, nil\n}\n\n// Write writes a \"PID file\" at the specified path. It returns an error if the\n// file exists and contains a valid PID of a running process, or when failing\n// to write the file.\nfunc Write(path string, pid int) error {\n\tif pid < 1 {\n\t\treturn fmt.Errorf(\"invalid PID (%d): only positive PIDs are allowed\", pid)\n\t}\n\toldPID, err := Read(path)\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn err\n\t}\n\tif oldPID != 0 {\n\t\treturn fmt.Errorf(\"process with PID %d is still running\", oldPID)\n\t}\n\treturn os.WriteFile(path, []byte(strconv.Itoa(pid)), 0o644)\n}\n","sourceCodeStart":46,"sourceCodeEnd":68,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/pidfile/pidfile.go#L46-L68","documentation":"pidfile.Write implements single-instance locking: it reads the existing pidfile, and Read returns a non-zero PID only when that PID is currently alive (see the alive(pid) check feeding this path). A live old PID means another instance holds the lock, so Write refuses to overwrite the file. This is intentional mutual exclusion, not corruption.","triggerScenarios":"Starting a second instance while the first is running: same --pidfile path, previous process still alive. Also when the old process died but its PID was reused by an unrelated live process (PID-reuse race).","commonSituations":"docker compose up twice in parallel with the same pidfile; a crashed run left the file and the PID got recycled; daemons/systemd restarting a service before the old one fully exited; stale pidfiles on hosts with fast PID cycling (containers).","solutions":["Stop the running instance first (kill <oldPID>, or the service's stop command), then start again.","Confirm the PID is genuinely yours: ps -p <oldPID>; if it is an unrelated process (PID reuse), remove the stale pidfile manually and retry.","Wire the pidfile path into your init system so restarts handle cleanup (systemd manages this without pidfiles).","Have your supervisor wait for process exit (e.g. ExecStop/killwait) before restarting."],"exampleFix":"# before\n$ mydaemon --pidfile /run/app.pid   # second instance: process with PID 4242 is still running\n\n# after\n$ kill 4242 && mydaemon --pidfile /run/app.pid\n# if 4242 is unrelated (PID reuse): rm /run/app.pid && mydaemon --pidfile /run/app.pid","handlingStrategy":"try-catch","validationCode":"if oldPID, err := pidfile.Read(path); err == nil && oldPID != 0 {\n    if syscall.Kill(oldPID, 0) == nil {\n        return fmt.Errorf(\"another instance is running as PID %d; stop it first\", oldPID)\n    }\n}","typeGuard":"func instanceHoldsLock(path string) (int, bool) {\n    pid, err := pidfile.Read(path)\n    return pid, err == nil && pid != 0\n}","tryCatchPattern":"if err := pidfile.Write(path, os.Getpid()); err != nil {\n    if strings.Contains(err.Error(), \"is still running\") {\n        // single-instance lock held: exit cleanly, do not delete the file\n        return err\n    }\n    return err\n}","preventionTips":["Always stop the previous instance before starting a new one.","Before removing a 'stale' pidfile, verify with ps that the PID is not a reused live process.","Let systemd/supervisors own lifecycle instead of hand-rolled pidfiles where possible."],"tags":["pidfile","single-instance","process","locking","go"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}