{"record":{"id":"6a97f9bdb1005e37","repo":"gastownhall/beads","slug":"classify-child-count-target-in-issues-w","errorCode":null,"errorMessage":"classify child-count target in issues: %w","messagePattern":"classify child-count target in issues: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/close.go","lineNumber":273,"sourceCode":"\nfunc releaseCloseCheckedSavepoint(ctx context.Context, tx DBTX, name string) error {\n\t//nolint:gosec // G201: name is generated by createCloseCheckedSavepoint.\n\tif _, err := tx.ExecContext(ctx, \"RELEASE SAVEPOINT \"+name); err != nil {\n\t\treturn fmt.Errorf(\"release checked close savepoint: %w\", err)\n\t}\n\treturn nil\n}\n\n// dependencyTargetColumnForIDInTx returns the typed target column for id,\n// preferring a durable row when an id is present in both tables.\nfunc dependencyTargetColumnForIDInTx(ctx context.Context, tx DBTX, id string) (string, error) {\n\tvar found int\n\terr := tx.QueryRowContext(ctx, \"SELECT 1 FROM issues WHERE id = ?\", id).Scan(&found)\n\tif err == nil {\n\t\treturn \"depends_on_issue_id\", nil\n\t}\n\tif !errors.Is(err, sql.ErrNoRows) {\n\t\treturn \"\", fmt.Errorf(\"classify child-count target in issues: %w\", err)\n\t}\n\terr = tx.QueryRowContext(ctx, \"SELECT 1 FROM wisps WHERE id = ?\", id).Scan(&found)\n\tif err == nil {\n\t\treturn \"depends_on_wisp_id\", nil\n\t}\n\tif optionalBlockedTable(\"wisps\") && isTableNotExistError(err) {\n\t\treturn \"depends_on_issue_id\", nil\n\t}\n\tif !errors.Is(err, sql.ErrNoRows) {\n\t\treturn \"\", fmt.Errorf(\"classify child-count target in wisps: %w\", err)\n\t}\n\treturn \"depends_on_issue_id\", nil\n}\n\n// isClosedInTx reports whether the issue (or wisp) identified by id exists and\n// is already closed. It probes the issues table then the optional wisps table,\n// mirroring IsBlockedInTx's table order.\n//","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/close.go#L255-L291","documentation":"Beads throws this when the probe 'SELECT 1 FROM issues WHERE id = ?' used to classify a close-policy target fails with a non-'no rows' error. Only sql.ErrNoRows is an acceptable outcome (meaning the id is not a durable issue); any other driver error is wrapped and aborts target classification for the open-children count.","triggerScenarios":"countOpenChildrenInTx → dependencyTargetColumnForIDInTx when the issues table is unreadable: missing issues table (error 1146 without optional-table gating applying — issues is not optional), permission denied, connection failure, lock timeout, or context cancellation during the probe.","commonSituations":"Database connection dropped mid-close; schema so broken the issues table is missing; another process holds locks on issues; context deadline exceeded on a slow server.","solutions":["Read the wrapped driver error after 'classify child-count target in issues:' for the root cause","Restore connectivity / retry the close if the cause was transient","Run schema checks/migrations if issues is reported missing — unlike wisp tables, issues is mandatory","Widen or remove context deadlines if the probe times out"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: issues is mandatory; verify it exists and is readable\nvar one int\nif err := db.QueryRow(\"SELECT 1 FROM issues LIMIT 1\").Scan(&one); err != nil {\n\treturn fmt.Errorf(\"issues table not readable (run migrations?): %w\", err)\n}","typeGuard":null,"tryCatchPattern":"count, err := countOpenChildrenInTx(ctx, tx, id)\nif err != nil {\n\tif errors.Is(err, context.DeadlineExceeded) || dberrors.IsConnectionError(err) || dberrors.IsLockTimeout(err) {\n\t\treturn retryClose(ctx, id)\n\t}\n\treturn fmt.Errorf(\"close of %s failed: %w\", id, err)\n}","preventionTips":["Apply migrations so the mandatory issues table always exists before using beads","Set context timeouts appropriate for your database latency","Retry closes on transient connection/lock errors — they are transactional","Monitor DB privileges after role changes; SELECT on issues is required"],"tags":["sql","database","classification"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}