{"record":{"id":"482dfff69fba3c5e","repo":"plandex-ai/plandex","slug":"error-getting-rows-affected","errorCode":null,"errorMessage":"Error getting rows affected: ","messagePattern":"Error getting rows affected: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_changes.go","lineNumber":467,"sourceCode":"\n\tif plan.ArchivedAt != nil {\n\t\tlog.Println(\"Plan already archived\")\n\t\thttp.Error(w, \"Plan already archived\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tres, err := db.Conn.Exec(\"UPDATE plans SET archived_at = NOW() WHERE id = $1\", planId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error archiving plan: %v\\n\", err)\n\t\thttp.Error(w, \"Error archiving plan: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\trowsAffected, err := res.RowsAffected()\n\tif err != nil {\n\t\tlog.Printf(\"Error getting rows affected: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting rows affected: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif rowsAffected == 0 {\n\t\tlog.Println(\"Plan not found\")\n\t\thttp.Error(w, \"Not found\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully archived plan\", planId)\n}\n\nfunc UnarchivePlanHandler(w http.ResponseWriter, r *http.Request) {\n\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\treturn\n\t}\n","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_changes.go#L449-L485","documentation":"After the archive UPDATE succeeded, res.RowsAffected() returned an error, so the handler responds HTTP 500 with 'Error getting rows affected'. With lib/pq this happens when the result has no row-count data (e.g. the driver couldn't report rows affected for the statement).","triggerScenarios":"Calling RowsAffected on a driver result that doesn't support it — typically a driver/dialect mismatch, or a connection/driver error surfacing when inspecting the result of the archive UPDATE.","commonSituations":"Using a driver whose RowsAffected is unimplemented/limited for the statement; a connection reset between Exec and RowsAffected; swapping database drivers without updating handler assumptions.","solutions":["Check the appended err.Error() for the driver-specific reason","Verify the expected Postgres driver (lib/pq or pgx stdlib) is in use — some drivers don't support RowsAffected for all statements","If the driver can't report rows, use a RETURNING clause or a SELECT count instead","Retry the request; if persistent, pin/upgrade the driver version"],"exampleFix":"// before\nres, err := db.Conn.Exec(\"UPDATE plans SET archived_at = NOW() WHERE id = $1\", planId)\nrows, _ := res.RowsAffected()\n// after\nvar updated int\nerr := db.Conn.QueryRow(\"UPDATE plans SET archived_at = NOW() WHERE id = $1 RETURNING 1\", planId).Scan(&updated)\nfound := err == nil","handlingStrategy":"fallback","validationCode":"const plan = await getPlan(planId);\nif (!plan) throw new Error('Plan not found before archive call');","typeGuard":"function isDriverResult(v) { return v !== null && typeof v === 'object' && typeof v.RowsAffected === 'function'; }","tryCatchPattern":"try { await archivePlan(planId); } catch (e) { if (e.status === 500 && /rows affected/i.test(e.message)) { // driver couldn't report count; verify state and continue\n  const p = await getPlan(planId); if (p?.archivedAt) return; } throw e; }","preventionTips":["Prefer RETURNING clauses over RowsAffected when driver support is uncertain","Pin/verify the Postgres driver version used by the server","After ambiguous archive errors, re-fetch the plan to confirm actual state","Add integration tests covering RowsAffected behavior of the chosen driver"],"tags":["database","postgresql","go","driver","internal-server-error"],"backgroundTag":"rows-affected-unsupported","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}