{"record":{"id":"8a9cc9f6491f5e5b","repo":"gastownhall/beads","slug":"timeout-waiting-for-proxy-to-become-ready-on-s","errorCode":null,"errorMessage":"timeout waiting for proxy to become ready on %s","messagePattern":"timeout waiting for proxy to become ready on (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/endpoint.go","lineNumber":404,"sourceCode":"\t\t\t\t\topts.Port, opts.LogFilePath, childErr,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn Endpoint{}, fmt.Errorf(\n\t\t\t\t\"proxy child exited before publishing its OS-assigned port (see %s): %w\",\n\t\t\t\topts.LogFilePath, childErr,\n\t\t\t)\n\t\tcase <-hard.C:\n\t\t\tif err := killSpawnedChild(child); err != nil {\n\t\t\t\treturn Endpoint{}, fmt.Errorf(\"hard timeout waiting for proxy on %s; safe child kill failed: %w\", describeSpawnPort(opts.Port), err)\n\t\t\t}\n\t\t\treturn Endpoint{}, fmt.Errorf(\"hard timeout (%s) waiting for proxy on %s\", spawnReadyHardTimeout, describeSpawnPort(opts.Port))\n\t\tcase <-poll.C:\n\t\t}\n\t\tif time.Now().After(deadline) {\n\t\t\tif err := killSpawnedChild(child); err != nil {\n\t\t\t\treturn Endpoint{}, fmt.Errorf(\"timeout waiting for proxy on %s; safe child kill failed: %w\", describeSpawnPort(opts.Port), err)\n\t\t\t}\n\t\t\treturn Endpoint{}, fmt.Errorf(\"timeout waiting for proxy to become ready on %s\", describeSpawnPort(opts.Port))\n\t\t}\n\t}\n}\n\n// describeSpawnPort renders a requested spawn port for wait/timeout\n// messages: 0 is the default OS-assigned path, not a literal \"port 0\".\nfunc describeSpawnPort(port int) string {\n\tif port == 0 {\n\t\treturn \"its OS-assigned port\"\n\t}\n\treturn fmt.Sprintf(\"port %d\", port)\n}\n\ntype spawnedProxyChild struct {\n\tcmd    *exec.Cmd\n\tdone   <-chan error\n\thandle *procid.Handle\n\tmarker spawnMarker","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/endpoint.go#L386-L422","documentation":"Returned by spawnAndHandoff when the caller's deadline expires while waiting for the spawned proxy to become ready and the child was killed cleanly. It is the normal (non-hard-timeout) startup-timeout outcome and reports which port the proxy was expected on.","triggerScenarios":"The poll loop in spawnAndHandoff observes time.Now().After(deadline) before the child publishes a dialable endpoint: backend initialization is slow, the child hangs, or the readiness record is never written.","commonSituations":"Very large or cold Dolt database; slow/NFS-backed workspace; overloaded machine; caller set an unrealistically short deadline; a wedged dolt subprocess inside the child blocking readiness.","solutions":["Check the child log (opts.LogFilePath) and discovery records under the workspace root for partial startup progress.","Increase the deadline passed into the open call to reflect actual cold-start cost.","Retry — after cleanup the next attempt often succeeds faster (warm caches).","Ensure no other process is interfering (stale locks, antivirus, resource limits) and that the workspace is on local disk where possible."],"exampleFix":"// before: 5s deadline for a 20s cold start\nctxDeadline := time.Now().Add(5 * time.Second)\n// after: derive deadline from observed cold-start time\ncoldStart := 30 * time.Second\nctxDeadline := time.Now().Add(coldStart)","handlingStrategy":"retry","validationCode":"deadline := time.Now().Add(coldStartBudget) // size budget to your environment\nif time.Until(deadline) < minReasonableSpawnWindow {\n    return errors.New(\"deadline too short for proxy cold start\")\n}","typeGuard":null,"tryCatchPattern":"ep, err := GetCreateDatabaseProxyServerEndpoint(rootDir, opts)\nif err != nil && strings.Contains(err.Error(), \"timeout waiting for proxy to become ready\") {\n    log.Printf(\"spawn timed out; child log at %s\", opts.LogFilePath)\n    time.Sleep(time.Second)\n    ep, err = GetCreateDatabaseProxyServerEndpoint(rootDir, opts)\n}","preventionTips":["Set deadlines from measured cold-start times, not guesses","Keep the workspace on fast local storage","Check the child log after every timeout — readiness failure is usually logged there","Warm caches by reusing a long-lived proxy instead of repeated cold starts"],"tags":["go","process-spawn","timeout","deadline"],"backgroundTag":"startup-timeout","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}