plandex-ai/plandex · info
shared.NoBuildsErr
Error message
shared.NoBuildsErr
What it means
When modelPlan.Build succeeds but reports numBuilds == 0, there was nothing pending to build (no queued file changes from a prior tell). The handler responds 404 with shared.NoBuildsErr (the client SDK recognizes this sentinel string) and logs an info-level notification. It is an expected 'nothing to do' outcome, not a fault.
Source
Thrown at app/server/handlers/plans_exec.go:205
Plan: plan,
Branch: branch,
Auth: auth,
SessionId: requestBody.SessionId,
OrgUserConfig: orgUserConfig,
Settings: settings,
})
if err != nil {
log.Printf("Error building plan: %v\n", err)
go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error building plan: %v", err))
http.Error(w, "Error building plan", http.StatusInternalServerError)
return
}
if numBuilds == 0 {
log.Println("No builds were executed")
go notify.NotifyErr(notify.SeverityInfo, fmt.Errorf("no builds were executed"))
http.Error(w, shared.NoBuildsErr, http.StatusNotFound)
return
}
if requestBody.ConnectStream {
startResponseStream(r.Context(), w, auth, planId, branch, false)
}
log.Println("Successfully processed request for BuildPlanHandler")
}
func ConnectPlanHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Received request for ConnectPlanHandler", "ip:", host.Ip)
vars := mux.Vars(r)
planId := vars["planId"]
branch := vars["branch"]
log.Println("planId: ", planId)
log.Println("branch: ", branch)View on GitHub (pinned to e2d772072e)
Solutions
- Treat the NoBuildsErr 404 as a benign no-op — check the response body for the sentinel string and continue.
- Run `plandex tell` first if you expect changes; build only processes output from a tell.
- De-duplicate automation so build is invoked once per tell, ideally driven by the stream completion event.
- Poll build status (GetBuildStatus) instead of re-invoking build when unsure whether builds are pending.
Example fix
// before: blindly retrying the 404
if err != nil { return retry() }
// after: recognize the no-builds sentinel
if res.StatusCode == 404 && strings.Contains(res.Body, shared.NoBuildsErr) {
return nil // nothing pending; not an error
} Defensive patterns
Strategy: type-guard
Validate before calling
// check for pending builds via status endpoint instead of invoking build blindly res, _ := http.Get(baseURL + "/plans/" + planId + "/branch/" + branch + "/build_status")
Type guard
func isNoBuildsErr(statusCode int, body string) bool {
return statusCode == http.StatusNotFound && strings.Contains(body, shared.NoBuildsErr)
} Try / catch
if res.StatusCode == 404 && isNoBuildsErr(res.StatusCode, res.Body) {
return nil // benign: nothing to build
}
if res.StatusCode != 200 { return fmt.Errorf("build failed: %s", res.Body) } Prevention
- Always special-case the NoBuildsErr sentinel before generic error handling.
- Trigger build only from a preceding tell or stream-completion event.
- De-duplicate scheduled/CI build invocations.
- Poll build status rather than re-issuing build calls to check progress.
When it happens
Trigger: Calling the build endpoint when no tell has queued any changes, after builds already ran to completion (double-build), or after the previous build consumed all pending updates.
Common situations: CI scripts invoking build twice; client retrying a build after a successful stream ended; automation assuming build is idempotent; race where another client built first.
Related errors
- Error building plan
- failed to build plan: %v
- failed to build plan: %v
- error building plan: %v
- error setting plan status to building: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/2b53e8f9c81972ee.
Report an issue: GitHub.