gastownhall/beads · error
child exited without reporting an error
Error message
child exited without reporting an error
What it means
This error replaces a nil child error when the managed proxy child process exits without reporting a failure, preventing an uninformative nil from masking a real startup problem. spawnAndHandoff raises it when the child died but wrote no error; the actual cause is then located via the child's log path (attached for non-LockHeldExitCode exits).
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:371
discovered := readAndDial(rootDir)
if discovered.status == adoptionAdopted {
if err := sweepOldQuarantines(rootDir, time.Now()); err != nil {
log.Printf("dbproxy: could not sweep old quarantined records in %s: %v", rootDir, err)
}
return discovered.endpoint, nil
}
if discovered.status == adoptionIOErr {
return Endpoint{}, fmt.Errorf("discover spawned proxy: %w", discovered.err)
}
select {
case childErr := <-child.done:
if interrupted, ierr := stopEpochChanged(rootDir, stopEpoch); ierr != nil {
return Endpoint{}, ierr
} else if interrupted {
return Endpoint{}, fmt.Errorf("%w for %s", errStartInterrupted, rootDir)
}
if childErr == nil {
childErr = errors.New("child exited without reporting an error")
}
// A LockHeldExitCode exit is a lost spawn race, not a listen
// failure; any other exit gets the child's log path so the real
// error (listen, backend start, ...) is findable.
var exitErr *exec.ExitError
if errors.As(childErr, &exitErr) && exitErr.ExitCode() == LockHeldExitCode {
return Endpoint{}, fmt.Errorf(
"proxy child lost the proxy.lock spawn race for %s: %w",
rootDir, childErr,
)
}
if opts.Port != 0 {
return Endpoint{}, fmt.Errorf(
"proxy child exited before becoming ready on explicitly configured port %d (see %s): %w",
opts.Port, opts.LogFilePath, childErr,
)
}
return Endpoint{}, fmt.Errorf(View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the child log path included in the wrapped error to find the real failure
- Re-run the start after checking resources (memory, disk, binary availability)
- If ExitCode is LockHeldExitCode, treat it as a lost spawn race and retry instead
Example fix
// before
ep, err := GetCreateDatabaseProxyServerEndpoint(ctx, root)
if err != nil { return err }
// after
ep, err := GetCreateDatabaseProxyServerEndpoint(ctx, root)
if err != nil {
var ee *exec.ExitError
if errors.As(err, &ee) && ee.ExitCode() == LockHeldExitCode {
return GetCreateDatabaseProxyServerEndpoint(ctx, root) // lost race, retry
}
return fmt.Errorf("proxy spawn failed: %w", err) // err mentions child log path
} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(childLogPath); err == nil { // inspect log before retrying } Type guard
func isSilentChildExit(err error) bool { return strings.Contains(err.Error(), "child exited without reporting an error") } Try / catch
ep, err := GetCreateDatabaseProxyServerEndpoint(ctx, root)
if err != nil {
var ee *exec.ExitError
if errors.As(err, &ee) && ee.ExitCode() == LockHeldExitCode { return retry() }
log.Errorf("proxy spawn failed (see child log in error): %v", err)
return err
} Prevention
- Keep child logs on disk and readable
- Monitor for OOM kills and signal deaths of children
- Handle LockHeldExitCode as a retryable lost race
When it happens
Trigger: Child proxy process exits during spawnAndHandoff with exit code other than LockHeldExitCode and without writing its error to the handoff channel or log.
Common situations: Child killed by a signal (OOM killer, external kill) before it could report; binary crash before logging; environment problems (bad PATH, missing Dolt binary) causing silent early exit.
Related errors
- fork child: %w
- pidfile: invalid pid
- ErrUnverifiableProcess
- port %d is in use by a non-dolt process (PID %d).\n\n%s\n\nF
- dolt sql-server exited immediately on port %d (attempt %d/%d
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f0ccdc34348c054c.
Report an issue: GitHub.