gastownhall/beads · error

read backend record %s: %w

Error message

read backend record %s: %w

What it means

cleanupOrphanBackend reads the Dolt backend PID record (pidfile) at <rootDir>/<PIDFileName> to decide whether a stale backend process must be killed. This error wraps any read failure that is NOT a malformed-record error (malformed records are routed to unverifiableProcessError instead). It signals the cleanup pass could not even inspect the record, so orphan cleanup was aborted.

Source

Thrown at internal/storage/dbproxy/proxy/endpoint.go:779

		return fmt.Errorf(
			"refusing backend cleanup: %s is held while proxy lock is free (recorded pid %d at %s); stop the process holding the child lock or remove the stale lock owner before retrying",
			childLockPath, pid, recordPath,
		)
	default:
		return fmt.Errorf("probe backend lock %s: %w", childLockPath, lockErr)
	}

	if readErr != nil {
		if isMalformedPIDFileError(readErr) {
			return unverifiableProcessError(
				"backend cleanup",
				recordPath,
				0,
				readErr,
				unverifiableProcessChecks{},
			)
		}
		return fmt.Errorf("read backend record %s: %w", recordPath, readErr)
	}
	if pf == nil {
		return nil
	}
	if err := pf.ValidateV2(pidfile.KindDoltBackend); err != nil {
		dead, live, probeErr := probeUnverifiablePID(pf.Pid)
		if dead {
			if _, quarantineErr := quarantineRecord(rootDir, server.PIDFileName, time.Now()); quarantineErr != nil {
				return fmt.Errorf("quarantine dead unverifiable backend record: %w", quarantineErr)
			}
			return nil
		}
		if probeErr != nil {
			err = errors.Join(err, fmt.Errorf("probe recorded pid: %w", probeErr))
		}
		return unverifiableProcessError(
			"backend cleanup",
			recordPath,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check permissions and ownership of the record file shown in the message and fix them (chown/chmod) so the current user can read it.
  2. Verify the file is a valid pidfile; if it is corrupt or stale, remove or rename it (e.g. to <record>.stale-<timestamp>) and retry.
  3. Re-run the command under the same user that created the workspace; avoid mixing sudo and non-sudo bd invocations.
  4. If the underlying OS error persists, investigate the filesystem (disk full, mount issues) reported by the wrapped cause.

Example fix

// before (record unreadable)
$ bd doctor
Error: read backend record /ws/.beads/dbproxy/dolt-backend.pid: open ...: permission denied
// after
$ sudo chown $(whoami) /ws/.beads/dbproxy/dolt-backend.pid
$ bd doctor  # cleanup proceeds
Defensive patterns

Strategy: validation

Validate before calling

recordPath := filepath.Join(rootDir, "dolt-backend.pid")
if _, err := os.Stat(recordPath); err != nil {
    if errors.Is(err, fs.ErrNotExist) {
        return nil // nothing to clean
    }
    return fmt.Errorf("record %s not readable before cleanup: %w", recordPath, err)
}

Type guard

func isMalformed(err error) bool {
    var target *fs.PathError
    return errors.As(err, &target) && errors.Is(target.Err, os.ErrPermission)
}

Try / catch

if err := cleanupOrphanBackend(rootDir); err != nil {
    var pathErr *fs.PathError
    if errors.As(err, &pathErr) && errors.Is(pathErr.Err, os.ErrPermission) {
        // surface guidance: fix ownership/permissions of pathErr.Path
    }
    return err
}

Prevention

When it happens

Trigger: pidfile.Read returns an error other than a malformed-PID-file error: the record file exists but is unreadable (permission denied, I/O error), or an unexpected filesystem error occurs while opening/decoding it at internal/storage/dbproxy/proxy/endpoint.go:749,779.

Common situations: File permissions changed on the workspace .beads/dbproxy directory (e.g. record written by a different user or root); disk/IO errors; a partially-written record whose decode fails in a way not classified as malformed; running bd from a different account after a sudo invocation.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/8d29077e84342bce. Report an issue: GitHub.