{"record":{"id":"dc47b42ef5ab45f4","repo":"bytebase/bytebase","slug":"failed-to-refresh-active-stale-plan-check-run-for","errorCode":null,"errorMessage":"failed to refresh active stale plan check run for approval input version","messagePattern":"failed to refresh active stale plan check run for approval input version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/component/review/evaluator.go","lineNumber":669,"sourceCode":"\t\tif planCheckRun.Status == store.PlanCheckRunStatusAvailable || planCheckRun.Status == store.PlanCheckRunStatusRunning {\n\t\t\tif planCheckRun.Result.GetApprovalInputVersion() == approvalInputVersion {\n\t\t\t\treturn nil, approvalInputVersion, false, nil\n\t\t\t}\n\t\t\trefreshed, err := stores.CreatePlanCheckRun(ctx, &store.PlanCheckRunMessage{\n\t\t\t\tProjectID: issue.ProjectID,\n\t\t\t\tPlanUID:   plan.UID,\n\t\t\t\tResult: &storepb.PlanCheckRunResult{\n\t\t\t\t\tApprovalInputVersion: approvalInputVersion,\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tslog.Error(\"failed to refresh active stale plan check run for approval input version\",\n\t\t\t\t\tslog.String(\"project\", issue.ProjectID),\n\t\t\t\t\tslog.Int64(\"issue_uid\", issue.UID),\n\t\t\t\t\tslog.Int64(\"plan_uid\", plan.UID),\n\t\t\t\t\tslog.Int64(\"approval_input_version\", approvalInputVersion),\n\t\t\t\t\tlog.BBError(err))\n\t\t\t\treturn nil, approvalInputVersion, false, errors.Wrap(err, \"failed to refresh active stale plan check run for approval input version\")\n\t\t\t}\n\t\t\t_ = refreshed\n\t\t\treturn nil, approvalInputVersion, false, nil\n\t\t}\n\t\tcurrent, pending := isPlanCheckRunCurrentForApprovalInputVersion(planCheckRun, approvalInputVersion)\n\t\tif pending {\n\t\t\treturn nil, approvalInputVersion, false, nil\n\t\t}\n\t\tif !current {\n\t\t\trefreshed, err := stores.RefreshPlanCheckRunIfStaleApprovalInputVersion(ctx, issue.ProjectID, plan.UID, approvalInputVersion)\n\t\t\tif err != nil {\n\t\t\t\tslog.Error(\"failed to refresh stale plan check run for approval input version\",\n\t\t\t\t\tslog.String(\"project\", issue.ProjectID),\n\t\t\t\t\tslog.Int64(\"issue_uid\", issue.UID),\n\t\t\t\t\tslog.Int64(\"plan_uid\", plan.UID),\n\t\t\t\t\tslog.Int64(\"approval_input_version\", approvalInputVersion),\n\t\t\t\t\tlog.BBError(err))\n\t\t\t\treturn nil, approvalInputVersion, false, errors.Wrap(err, \"failed to refresh stale plan check run for approval input version\")","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/component/review/evaluator.go#L651-L687","documentation":"Error refreshing a plan check run whose status is still Available/Running but whose stored approval input version no longer matches the plan's current one (the plan changed mid-flight). The evaluator creates a fresh check run so the scheduler re-checks against the new inputs; failure is logged with structured fields and wrapped.","triggerScenarios":"planCheckRun is Available/Running with a stale ApprovalInputVersion, and CreatePlanCheckRun fails while writing the replacement: unique-constraint race, metadata write failure, or connection loss.","commonSituations":"Plan edited while its check was running; two evaluators racing to refresh the same stale row; metadata DB read-only/full disk; deadlock with the check scheduler updating the same row.","solutions":["If the wrapped cause is a duplicate-key error, re-read the plan check run — the concurrent refresher likely succeeded.","Verify metadata Postgres accepts writes (read-only mode, disk space).","Retry the evaluation after transient failures.","Serialize refreshes per-plan (advisory lock or single-writer scheduler) to avoid races."],"exampleFix":"// before\n_, err := stores.CreatePlanCheckRun(ctx, msg)\nif err != nil { return errors.Wrap(err, \"failed to refresh active stale plan check run...\") }\n// after: upsert instead of insert\n_, err := stores.UpsertPlanCheckRun(ctx, msg) // ON CONFLICT (project, plan_uid) DO UPDATE\nif err != nil { return errors.Wrap(err, \"...\") }","handlingStrategy":"retry","validationCode":"// detect stale version before refreshing\ncurrent, pending := isPlanCheckRunCurrentForApprovalInputVersion(planCheckRun, approvalInputVersion)\nif pending || current { return nil } // no refresh needed","typeGuard":null,"tryCatchPattern":"if _, err := stores.CreatePlanCheckRun(ctx, msg); err != nil {\n    if isUniqueViolation(err) { return nil } // another refresher won\n    slog.Error(\"failed to refresh active stale plan check run\", log.BBError(err))\n    return errors.Wrap(err, \"failed to refresh active stale plan check run for approval input version\")\n}","preventionTips":["Avoid editing plans while checks are running; bump approval input version deliberately.","Use upsert semantics for refresh rows.","Serialize refreshes per plan with an advisory lock.","Verify DB writability (disk space, read-only mode) before bulk refreshes."],"tags":["database","concurrency","go"],"backgroundTag":"database-write-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}