{"record":{"id":"093dc09639692baa","repo":"gastownhall/beads","slug":"dolt-sql-server-exited-before-listener-became-read","errorCode":null,"errorMessage":"dolt sql-server exited before listener became ready","messagePattern":"dolt sql-server exited before listener became ready","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/storage/dbproxy/server/doltserver.go","lineNumber":323,"sourceCode":"\t\tdefer lock.Unlock()\n\t\treturn cmd.Wait()\n\t})\n\n\tif err := s.waitReady(ctx); err != nil {\n\t\tcancel()\n\t\t_ = s.eg.Wait()\n\t\ts.eg, s.egCtx, s.cancel, s.pid = nil, nil, nil, 0\n\t\t_ = pidfile.Remove(s.rootDir, PIDFileName)\n\t\treturn fmt.Errorf(\"server: DoltServer.Start: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (s *DoltServer) waitReady(ctx context.Context) error {\n\tdeadline := time.Now().Add(startReadyTimeout)\n\tfor {\n\t\tif s.egCtx.Err() != nil {\n\t\t\treturn errors.New(\"dolt sql-server exited before listener became ready\")\n\t\t}\n\n\t\tdctx, dcancel := context.WithTimeout(ctx, startReadyDialTimeout)\n\t\tconn, err := s.Dial(dctx)\n\t\tdcancel()\n\t\tif err == nil {\n\t\t\t_ = conn.Close()\n\t\t\treturn nil\n\t\t}\n\n\t\tif time.Now().After(deadline) {\n\t\t\treturn fmt.Errorf(\"listener not ready after %s: %w\", startReadyTimeout, err)\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-s.egCtx.Done():","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/server/doltserver.go#L305-L341","documentation":"waitReady polls the server with TCP dials until the dolt sql-server listener accepts. If the child process exits (its errgroup context becomes done) before a dial succeeds, Start fails with this message. The actual reason the child died is not in this error — check the configured log file or the child's stderr for the real cause.","triggerScenarios":"Calling DoltServer.Start when the spawned `dolt sql-server` process exits during the readiness window (30s, polled every 50ms): bad YAML server config, port already bound by another process, dolt binary fails to launch, data directory locked/corrupt, or another waitReady caller's egCtx was cancelled.","commonSituations":"Config file pointing at a port already used by another dolt/MySQL server; malformed server.yaml accepted by parse but rejected at runtime; missing or wrong-arch dolt binary; two proxies racing on the same rootDir; dolt crashing on startup due to a corrupt or locked .dolt directory.","solutions":["Read the server log file (the logFilePath passed to NewDoltServer) for the child's actual exit reason","Check the configured port: ss -ltnp | grep <port> — kill the conflicting process or change the port in server.yaml","Verify the dolt binary runs: run `<doltBinExec> version` manually","Check the data directory for stale locks or corruption (bd doctor / dolt fsck)","Start again; if this recurs after fixing, inspect the YAML config for invalid runtime options"],"exampleFix":"// before\nsrv, _ := server.NewDoltServer(bin, root, \"server.yaml\", \"\", 0, db)\nif err := srv.Start(ctx); err != nil { return err } // opaque 'exited before listener became ready'\n// after\nsrv, _ := server.NewDoltServer(bin, root, \"server.yaml\", filepath.Join(root, \"dolt-server.log\"), 0, db)\nif err := srv.Start(ctx); err != nil {\n    log.Fatalf(\"%v; see %s for the dolt sql-server exit reason\", err, logPath)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(doltBinExec); err != nil { return fmt.Errorf(\"dolt binary missing: %w\", err) }\nout, err := exec.Command(doltBinExec, \"version\").CombinedOutput()\nif err != nil { return fmt.Errorf(\"dolt binary unusable: %w: %s\", err, out) }\n// port check\nif ln, err := net.Listen(\"tcp\", \":\"+port); err != nil { return fmt.Errorf(\"port %s in use\", port) } else { ln.Close() }","typeGuard":null,"tryCatchPattern":"if err := srv.Start(ctx); err != nil {\n    if strings.Contains(err.Error(), \"exited before listener became ready\") {\n        return fmt.Errorf(\"dolt sql-server failed to start; check server log at %s and port %d: %w\", logPath, port, err)\n    }\n    return err\n}","preventionTips":["Always configure logFilePath so the child's exit reason is captured","Verify the dolt binary exists and runs before Start","Check the configured port is free before startup; use a port-allocating config in tests","Ensure only one server owns a given rootDir (use the pidfile/lock files)","Validate server.yaml against the dolt version in use"],"tags":["go","process-spawn","server-startup","dolt","port-conflict"],"backgroundTag":"server-exited-before-ready","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}