gastownhall/beads · error
re-check proxy stop epoch before publish: %w
Error message
re-check proxy stop epoch before publish: %w
What it means
Wraps an error from the final stopEpochChanged re-check performed just before publishing proxy.pid. To avoid publishing a pidfile for a proxy that a concurrent stop is already tearing down, the epoch is re-read after cancelling the epoch watcher; if that read itself fails (not merely 'changed'), startup aborts with this error and the backend is stopped.
Source
Thrown at internal/storage/dbproxy/proxy/server.go:311
identReply.UpstreamID = upstreamID
identReply.PID = os.Getpid()
identReply.Birth = string(birth)
identReply.ControlPort = control.Port()
identMu.Unlock()
// Last fence before publishing: the spawn marker was cleared when this
// process took proxy.lock, so a `bd dolt stop` that began during a slow
// backend start has no record of this attempt. It did advance the stop
// epoch first, so re-check it here and abort instead of publishing a
// running proxy after that stop returned. The startup epoch watcher is
// stopped (synchronously) first: past this fence a stop finds the
// published proxy.pid and stops the proxy through it, so a watcher
// cancellation must not race the publish.
stopEpochWatch()
if changed, err := stopEpochChanged(p.rootDir, p.stopEpoch); err != nil {
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("re-check proxy stop epoch before publish: %w", err)
} else if changed {
return abortInterruptedStart()
}
if err := pidfile.Write(p.rootDir, PIDFileName, pidfile.PidFile{
Pid: os.Getpid(),
Port: dataPort.Port,
UpstreamID: upstreamID,
Schema: pidfile.SchemaV2,
Kind: pidfile.KindProxy,
Birth: string(birth),
RootID: rootID,
ControlPort: control.Port(),
}); err != nil {
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("write pid file: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Check disk health and filesystem errors in system logs (dmesg/journalctl)
- Verify rootDir and the epoch state file are readable by the proxy process
- Ensure nothing external (cleaner job, another tool) is deleting files in rootDir while the proxy starts
- Retry startup once the storage issue is resolved
Defensive patterns
Strategy: validation
Validate before calling
// Verify rootDir state files are readable before start
f, err := os.Open(filepath.Join(rootDir, "stop-epoch"))
if err != nil {
return fmt.Errorf("cannot read stop-epoch state: %w", err)
}
f.Close() Try / catch
if err := p.ListenAndServe(ctx); err != nil {
if strings.Contains(err.Error(), "re-check proxy stop epoch") {
log.Fatalf("storage I/O failure during startup: %v", err)
}
log.Fatal(err)
} Prevention
- Monitor disk health and filesystem error counters
- Prevent external cleanup jobs from touching rootDir while a proxy starts
- Run the proxy under the storage owner account with stable permissions
When it happens
Trigger: The stopEpochChanged(p.rootDir, p.stopEpoch) call after stopEpochWatch() returns an error - usually an I/O failure reading the stop-epoch state file under rootDir.
Common situations: rootDir became unwritable/unreadable (volume detached, permissions flipped); disk I/O errors on the host; concurrent deletion of the proxy state directory by an external cleaner.
Related errors
- failed to read backup state: %w
- failed to write temp file: %w
- failed to sync temp file: %w
- failed to write issue %s: %w
- failed to create output file: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/22ed532d2e6cff0c.
Report an issue: GitHub.