gastownhall/beads · error

resolve workspace identity: %w

Error message

resolve workspace identity: %w

What it means

This error wraps a failure from identity.RootID() while validating a pidfile kill-record during proxy shutdown. The proxy records the workspace root identity (derived from the root directory) in its pidfile and re-checks it before force-stopping a stale daemon. If the workspace root ID cannot be resolved (e.g. the directory is unreadable or has no stable identity), validation aborts with this wrapped error rather than killing a process with unknown ownership.

Source

Thrown at internal/storage/dbproxy/proxy/shutdown.go:377

		time.Sleep(shutdownConfirmPoll)
	}
}

func validateKillRecord(
	rootDir string,
	pf *pidfile.PidFile,
	wantKind string,
	checks killRecordChecks,
) error {
	if err := pf.ValidateV2(wantKind); err != nil {
		return err
	}
	if !checks.VerifyRoot {
		return nil
	}
	rootID, err := identity.RootID(rootDir)
	if err != nil {
		return fmt.Errorf("resolve workspace identity: %w", err)
	}
	if pf.RootID != rootID {
		return fmt.Errorf("root identity mismatch (record has %q, workspace has %q)", pf.RootID, rootID)
	}
	return nil
}

func classifyInvalidKillRecord(pf *pidfile.PidFile, validationErr error) (dead bool, live bool, err error) {
	if !isPIDFileValidationError(validationErr) {
		return false, false, nil
	}
	return probeUnverifiablePID(pf.Pid)
}

func isPIDFileValidationError(err error) bool {
	return errors.Is(err, pidfile.ErrLegacySchema) ||
		errors.Is(err, pidfile.ErrBadPid) ||
		errors.Is(err, pidfile.ErrBadPort) ||

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-create the workspace metadata so identity.RootID can resolve the root directory (run bd doctor or reinitialize the project in place).
  2. Verify the root directory exists, is readable by the current user, and was not renamed since the daemon started.
  3. Stop any stale daemon by hand (kill the recorded PID) and remove the stale pidfile, then restart.
  4. Check file permissions on the workspace root (ls -ld) and re-run with correct ownership.

Example fix

// before: root dir moved, pidfile references old identity
$ bd doctor
// after: restore/reinit workspace then retry
$ cd /correct/workspace && bd doctor && bd ...
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(rootDir); err != nil {
    return fmt.Errorf("workspace root unreadable before proxy stop: %w", err)
}
if _, err := identity.RootID(rootDir); err != nil {
    // resolve identity up front so validateKillRecord cannot fail
    return err
}

Try / catch

if _, err := stopAndAcquire(ctx); err != nil {
    if errors.Is(err, errIdentityUnresolvable) || strings.Contains(err.Error(), "resolve workspace identity") {
        // fall back to manual pidfile cleanup
    }
}

Prevention

When it happens

Trigger: stopAndAcquire -> validateKillRecord calls identity.RootID(rootDir), which returns an error (unreadable root dir, missing temp/lock artifacts the identity derivation depends on, permission issues).

Common situations: Running `bd` in a directory that was moved/renamed after the daemon started; running with insufficient permissions on the workspace root; deleting parts of the workspace (e.g. .beads metadata) that identity.RootID uses to derive a stable ID.

Related errors


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