gastownhall/beads · error

cannot spawn from proxy discovery status %s

Error message

cannot spawn from proxy discovery status %s

What it means

quarantineForSpawn only knows how to quarantine records in a fixed set of discovery statuses (no record, stale-dead, identity mismatch, unverifiable, legacy, malformed). Any other status — notably adoptionIOErr, which means the pidfile could not be read for an I/O reason — reaches the default case and aborts the spawn.

Source

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

	case adoptionIdentityMismatch:
		log.Printf(
			"dbproxy: refusing proxy identity at %s (%v); quarantining only its record and starting a fresh proxy",
			pidfile.Path(rootDir, PIDFileName), discovery.err,
		)
	case adoptionUnverifiable:
		log.Printf(
			"dbproxy: proxy identity at %s could not be verified (%v); quarantining only its record under proxy.lock and starting a fresh proxy",
			pidfile.Path(rootDir, PIDFileName), discovery.err,
		)
	case adoptionLegacy:
		log.Printf(
			"dbproxy: quarantining legacy proxy record %s; a pre-upgrade proxy may still be running and must be stopped with the old bd binary if it does not idle-exit",
			pidfile.Path(rootDir, PIDFileName),
		)
	case adoptionMalformed:
		log.Printf("dbproxy: quarantining malformed proxy record %s (%v) before restart", pidfile.Path(rootDir, PIDFileName), discovery.err)
	default:
		return fmt.Errorf("cannot spawn from proxy discovery status %s", discovery.status)
	}
	target, err := quarantineRecord(rootDir, PIDFileName, time.Now())
	if err != nil {
		return fmt.Errorf("quarantine proxy record: %w", err)
	}
	log.Printf("dbproxy: preserved proxy record as %s", target)
	return nil
}

func quarantineRecord(rootDir, name string, now time.Time) (string, error) {
	source := pidfile.Path(rootDir, name)
	for stamp := now.Unix(); ; stamp++ {
		target := filepath.Join(rootDir, name+".stale-"+strconv.FormatInt(stamp, 10))
		if _, err := os.Lstat(target); err == nil {
			continue
		} else if !errors.Is(err, fs.ErrNotExist) {
			return "", fmt.Errorf("inspect quarantine target %s: %w", target, err)
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped discovery.err (logged by earlier readAndDial path) to find the pidfile I/O error and fix permissions/disk state
  2. Check that the workspace root is writable by the current user and the pidfile is a regular file (ls -l)
  3. Free the file if held by another process (close editors/AV scanners) or unmount/remount a wedged network share
  4. If a version mismatch introduced the unknown status, upgrade or match bd binaries between parent/child

Example fix

// before
default:
    return fmt.Errorf("cannot spawn from proxy discovery status %s", discovery.status)
// after
case adoptionIOErr:
    return fmt.Errorf("cannot spawn from proxy discovery status %s: %w", discovery.status, discovery.err)
default:
    return fmt.Errorf("cannot spawn from proxy discovery status %s", discovery.status)
Defensive patterns

Strategy: try-catch

Type guard

func isSpawnableStatus(s adoptionStatus) bool {
    switch s {
    case adoptionNoRecord, adoptionStaleDead, adoptionIdentityMismatch,
        adoptionUnverifiable, adoptionLegacy, adoptionMalformed:
        return true
    }
    return false
}

Try / catch

if err := quarantineForSpawn(root, discovery); err != nil {
    var uerr *statusError
    if errors.As(err, &uerr) {
        log.Printf("pidfile I/O problem: %v", discovery.err) // fix perms/disk, then retry
    }
    return err
}

Prevention

When it happens

Trigger: spawnAndHandoff runs quarantineForSpawn(discovery) and discovery.status is adoptionIOErr (or any new status not in the switch) because pidfile.Read failed with a non-malformed I/O error on the proxy pidfile.

Common situations: Filesystem permission errors on the workspace directory; the pidfile path is a directory or is locked by another tool; NFS/Windows share I/O errors; a future bd version introduces a new adoption status while an older binary path runs.

Related errors


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