{"record":{"id":"8409febac30f5c20","repo":"plandex-ai/plandex","slug":"error-building-race-v","errorCode":null,"errorMessage":"error building race: %v","messagePattern":"error building race: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/model/plan/build_structured_edits.go","lineNumber":171,"sourceCode":"\t\t\tproposedContent: proposedContent,\n\t\t\tdesc:            desc,\n\t\t\treasons:         autoApplyRes.NeedsVerifyReasons,\n\t\t\tsyntaxErrors:    autoApplySyntaxErrors,\n\n\t\t\tdidCallFastApply: calledFastApply,\n\t\t\tfastApplyCh:      fastApplyCh,\n\n\t\t\tsessionId: activePlan.SessionId,\n\t\t}\n\n\t\tbuildRaceResult, err := fileState.buildRace(buildCtx, cancelBuild, buildRaceParams)\n\t\tif err != nil {\n\t\t\tif apiErr, ok := err.(*shared.ApiError); ok {\n\t\t\t\tactivePlan.StreamDoneCh <- apiErr\n\t\t\t\treturn\n\t\t\t} else {\n\t\t\t\tlog.Printf(\"buildStructuredEdits - %s - error building race: %v\\n\", filePath, err)\n\t\t\t\tfileState.onBuildFileError(fmt.Errorf(\"error building race: %v\", err))\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tupdated = buildRaceResult.content\n\t}\n\n\t// output diff and store build results\n\tbuildInfo := &shared.BuildInfo{\n\t\tPath:      filePath,\n\t\tNumTokens: 0,\n\t\tFinished:  true,\n\t}\n\tlog.Printf(\"streaming build info for finished file %s\\n\", filePath)\n\tactivePlan.Stream(shared.StreamMessage{\n\t\tType:      shared.StreamMessageBuildInfo,\n\t\tBuildInfo: buildInfo,\n\t})","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_structured_edits.go#L153-L189","documentation":"buildStructuredEdits wraps any failure returned by fileState.buildRace (the fallback LLM race that fixes a failed auto-apply) into \"error building race: %v\" and forwards it via fileState.onBuildFileError. It is thrown when the race of fast-apply/model-based repair paths fails for a non-ApiError reason, meaning the file's edits could not be finalized. If the underlying error is a *shared.ApiError it is instead streamed to activePlan.StreamDoneCh and this message is not produced.","triggerScenarios":"fileState.buildRace(buildCtx, cancelBuild, buildRaceParams) returns a non-nil error that is not *shared.ApiError — e.g. all racers in buildRace failed, LLM streaming call errored (network/timeout), or the repair candidates produced unusable output — while processing a file whose auto-apply had syntax errors or NeedsVerifyReasons.","commonSituations":"LLM provider outages or rate limits during the repair race, an invalid/expired auth token surfacing as a non-ApiError, malformed model responses that make every race branch fail, or context deadline exceeded on the build context.","solutions":["Check the wrapped inner error in the log line to identify the root cause (network, auth, or model output).","Verify LLM provider credentials and rate limits; if it's a transient network failure, retry the plan build.","If the underlying error is actually an API error, ensure it is typed as *shared.ApiError so it routes through StreamDoneCh instead of this path.","Increase build context timeout or reduce file size so the repair race can complete."],"exampleFix":"// before\nbuildRaceResult, err := fileState.buildRace(buildCtx, cancelBuild, buildRaceParams)\nif err != nil {\n    log.Printf(\"error building race: %v\", err)\n}\n// after\nbuildRaceResult, err := fileState.buildRace(buildCtx, cancelBuild, buildRaceParams)\nif err != nil {\n    var apiErr *shared.ApiError\n    if errors.As(err, &apiErr) {\n        activePlan.StreamDoneCh <- apiErr\n        return\n    }\n    if errors.Is(err, context.Canceled) {\n        return // user canceled, don't report as failure\n    }\n    log.Printf(\"error building race: %v\", err)\n}","handlingStrategy":"type-guard","validationCode":"// Pre-check inputs before entering the race path\nif updated == \"\" || proposedContent == \"\" {\n    return fmt.Errorf(\"cannot run build race with empty content\")\n}","typeGuard":"var apiErr *shared.ApiError\nif errors.As(err, &apiErr) {\n    // route to StreamDoneCh\n    activePlan.StreamDoneCh <- apiErr\n    return\n}\nif errors.Is(err, context.Canceled) {\n    return // not a real failure\n}","tryCatchPattern":"buildRaceResult, err := fileState.buildRace(buildCtx, cancelBuild, buildRaceParams)\nif err != nil {\n    var apiErr *shared.ApiError\n    switch {\n    case errors.As(err, &apiErr):\n        activePlan.StreamDoneCh <- apiErr\n    case errors.Is(err, context.Canceled):\n        // swallow cancellation\n    default:\n        fileState.onBuildFileError(fmt.Errorf(\"error building race: %w\", err))\n    }\n    return\n}","preventionTips":["Use errors.As/errors.Is instead of a raw type assertion so wrapped ApiErrors are recognized.","Handle context.Canceled explicitly so user cancellations aren't logged as build failures.","Monitor LLM provider health and rate limits before launching repair races.","Keep repair-race prompts and model configs validated in tests."],"tags":["llm","race","build-pipeline","error-wrapping"],"backgroundTag":"llm-build-race-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}