gastownhall/beads · error
pidfile: legacy schema
Error message
pidfile: legacy schema
What it means
ErrLegacySchema indicates a pidfile on disk uses schema v1 (or older) while the current dbproxy code requires schema v2. It is returned by PidFile.ValidateV2 (and readAndDial/stopAndAcquire which call it) when the parsed pidfile's Schema field is below SchemaV2, so the library refuses to trust legacy pidfiles that lack v2 fields like birth tokens.
Source
Thrown at internal/storage/dbproxy/pidfile/pidfile.go:32
Pid int `json:"pid"`
Port int `json:"port"`
UpstreamID string `json:"upstream_id,omitempty"`
Schema int `json:"schema,omitempty"`
Kind string `json:"kind,omitempty"`
Birth string `json:"birth,omitempty"`
RootID string `json:"root_id,omitempty"`
ControlPort int `json:"control_port,omitempty"`
}
const SchemaV2 = 2
const (
KindProxy = "db-proxy"
KindDoltBackend = "dolt-backend"
)
var (
ErrLegacySchema = errors.New("pidfile: legacy schema")
ErrBadPid = errors.New("pidfile: invalid pid")
ErrBadPort = errors.New("pidfile: invalid port")
ErrKindMismatch = errors.New("pidfile: kind mismatch")
ErrMissingBirth = errors.New("pidfile: missing birth token")
)
// ValidateV2 validates the fields required for a schema v2 pidfile.
func (p *PidFile) ValidateV2(wantKind string) error {
if p.Schema < SchemaV2 {
return ErrLegacySchema
}
if p.Pid <= 0 {
return ErrBadPid
}
if p.Port < 1 || p.Port > 65535 || (p.ControlPort != 0 && (p.ControlPort < 1 || p.ControlPort > 65535)) {
return ErrBadPort
}
if p.Kind != wantKind {View on GitHub (pinned to 71377f2769)
Solutions
- Delete the stale pidfile and restart the proxy so a fresh schema-v2 pidfile is written
- Upgrade all beads binaries sharing the workspace to the same (current) version
- Use errors.Is(err, pidfile.ErrLegacySchema) to detect the case and fall back to legacy cleanup/stop logic before re-acquiring
Example fix
// before
if err := pf.ValidateV2(pidfile.KindProxy); err != nil { return err }
// after
if err := pf.ValidateV2(pidfile.KindProxy); err != nil {
if errors.Is(err, pidfile.ErrLegacySchema) {
_ = os.Remove(pidfilePath) // drop v1 pidfile, re-acquire fresh
return acquireProxy(rootDir)
}
return err
} Defensive patterns
Strategy: type-guard
Validate before calling
data, _ := os.ReadFile(pidfilePath)
var pf pidfile.PidFile
json.Unmarshal(data, &pf)
if pf.Schema < pidfile.SchemaV2 { /* regenerate pidfile first */ } Type guard
func isLegacySchema(err error) bool { return errors.Is(err, pidfile.ErrLegacySchema) } Try / catch
if err := pf.ValidateV2(pidfile.KindProxy); err != nil {
if errors.Is(err, pidfile.ErrLegacySchema) { /* regenerate */ }
return err
} Prevention
- Keep all beads binaries in a workspace at the same version
- Clean up pidfiles when upgrading
- Never hand-edit pidfiles
When it happens
Trigger: Calling ValidateV2(wantKind) on a PidFile whose Schema < SchemaV2; readAndDial or stopAndAcquire reading a pidfile written by an older beads/dbproxy binary.
Common situations: Upgrading the beads binary while a stale proxy pidfile from the previous version remains on disk; mixed-version clusters where an old binary wrote the pidfile; restored workspaces from backups made by older versions.
Related errors
- failed to get parent-child deps from %s: %w
- no store is open for this workspace
- not found
- pidfile: invalid pid
- pidfile: invalid port
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/737de67aa2be797f.
Report an issue: GitHub.