gastownhall/beads · error

resolve proxy root identity: %w

Error message

resolve proxy root identity: %w

What it means

Wraps a failure of identity.RootID(p.rootDir), which resolves the stable root identity of the database directory used in the proxy's IdentReply. If the root identity file/record cannot be read or is invalid, the backend is stopped and startup aborts - the proxy refuses to advertise itself without a verifiable root identity.

Source

Thrown at internal/storage/dbproxy/proxy/server.go:288

	if err := waitForServerReady(ctx, p.server, serverReadyTimeout); err != nil {
		if changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {
			return abortInterruptedStart()
		}
		p.stats.IncBackendStop()
		_ = stopBackendBounded(p.server)
		return fmt.Errorf("database server not ready: %w", err)
	}
	birth, err := procid.Capture(os.Getpid())
	if err != nil {
		p.stats.IncBackendStop()
		_ = stopBackendBounded(p.server)
		return fmt.Errorf("capture proxy birth identity: %w", err)
	}
	rootID, err := identity.RootID(p.rootDir)
	if err != nil {
		p.stats.IncBackendStop()
		_ = stopBackendBounded(p.server)
		return fmt.Errorf("resolve proxy root identity: %w", err)
	}
	upstreamID := p.server.ID(ctx)
	identMu.Lock()
	identReply.RootID = rootID
	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.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-initialize or repair the database root (re-run init) so a valid root identity exists
  2. Restore the missing identity files from a known-good backup of rootDir
  3. Check file permissions on the identity metadata files in rootDir
  4. Confirm the tooling and proxy versions agree on the identity schema

Example fix

// before
// identity file missing after manual dir copy
$ cp -r /data/db /data/db-copy  # dropped hidden identity files
// after
$ bd init /data/db-copy  # or restore the full directory including identity metadata
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the root identity metadata exists before start
if _, err := os.Stat(filepath.Join(rootDir, ".beads_root_id")); os.IsNotExist(err) {
    return fmt.Errorf("root identity missing in %s; re-init the database", rootDir)
}

Try / catch

if err := p.ListenAndServe(ctx); err != nil {
    if strings.Contains(err.Error(), "resolve proxy root identity") {
        log.Fatalf("rootDir identity unreadable/incompatible: %v - re-run init", err)
    }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: ListenAndServe -> identity.RootID fails because the root metadata in rootDir is missing, corrupted, was written by an incompatible schema version, or is unreadable due to permissions.

Common situations: rootDir initialized by an older/newer beads version (schema drift); partially initialized directory where init was interrupted; manual copy of the database dir that dropped identity files; permission changes after backup/restore.

Related errors


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