{"record":{"id":"12e96c80dbcb3f3e","repo":"gastownhall/beads","slug":"db-childcountersqlrepository-nextchildid-scan-ex","errorCode":null,"errorMessage":"db: ChildCounterSQLRepository.NextChildID: scan existing children of %s: %w","messagePattern":"db: ChildCounterSQLRepository\\.NextChildID: scan existing children of (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/child_counter.go","lineNumber":59,"sourceCode":"\t\t//nolint:gosec // G201: counterTable is one of two hardcoded constants\n\t\tfmt.Sprintf(\"SELECT last_child FROM %s WHERE parent_id = ?\", counterTable),\n\t\tparentID,\n\t).Scan(&lastChild)\n\tswitch {\n\tcase err == nil:\n\tcase errors.Is(err, sql.ErrNoRows):\n\t\tlastChild = 0\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"db: ChildCounterSQLRepository.NextChildID: read counter for %s: %w\", parentID, err)\n\t}\n\n\trows, err := r.runner.QueryContext(ctx, fmt.Sprintf(`\n\t\tSELECT id FROM %s\n\t\tWHERE id LIKE CONCAT(?, '.%%')\n\t\t  AND id NOT LIKE CONCAT(?, '.%%.%%')\n\t`, issueTable), parentID, parentID) //nolint:gosec // G201: issueTable is one of two hardcoded constants\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"db: ChildCounterSQLRepository.NextChildID: scan existing children of %s: %w\", parentID, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"db: ChildCounterSQLRepository.NextChildID: scan: %w\", err)\n\t\t}\n\t\tif n, ok := parseChildSuffix(id); ok && n > lastChild {\n\t\t\tlastChild = n\n\t\t}\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"db: ChildCounterSQLRepository.NextChildID: rows: %w\", err)\n\t}\n\n\tnext := lastChild + 1\n\t//nolint:gosec // G201: counterTable is one of two hardcoded constants\n\tif _, err := r.runner.ExecContext(ctx, fmt.Sprintf(`","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/child_counter.go#L41-L77","documentation":"Wrapping error from ChildCounterSQLRepository.NextChildID at internal/storage/domain/db/child_counter.go:59. After reading the counter, the code queries all existing direct children of the parent (LIKE '<parent>.%' and not deeper) to reconcile the counter with reality. A failure executing that query (QueryContext error) is wrapped with this message. Row-scan failures later in the loop produce a separate 'scan:' variant.","triggerScenarios":"Calling NextChildID when the QueryContext listing direct children of parentID fails — connection dropped between the counter read and this query, SQL execution error, or the issue/wisp table is unreadable.","commonSituations":"Very large parent (many children) causing a slow query that hits a timeout; DB connection interrupted mid-operation; permissions issue on the issues/wisps table.","solutions":["Unwrap to see the underlying SQL/driver error","Check query timeouts if the parent has many children (index on id prefix)","Verify connection stability between the counter read and children scan","Retry once the database is reachable"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure the children listing query runs before generating a new child ID\nrows, err := store.QueryContext(ctx,\n\t\"SELECT id FROM issues WHERE id LIKE CONCAT(?, '.%') AND id NOT LIKE CONCAT(?, '.%.%')\",\n\tparentID, parentID)\nif err != nil {\n\treturn fmt.Errorf(\"children of %s unlistable: %w\", parentID, err)\n}\nrows.Close()","typeGuard":null,"tryCatchPattern":"id, err := repo.NextChildID(ctx, parentID)\nif err != nil && strings.Contains(err.Error(), \"scan existing children\") {\n\tif errors.Is(errors.Unwrap(err), context.DeadlineExceeded) {\n\t\tlongCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\t\tdefer cancel()\n\t\tid, err = repo.NextChildID(longCtx, parentID)\n\t}\n}\nreturn id, err","preventionTips":["Index the id column so prefix scans over large parents stay fast","Use a context deadline that tolerates many children under one parent","Check connection stability for multi-query operations","Retry transient query errors instead of failing the whole create flow"],"tags":["database","child-id","sql","query","error-wrapping"],"backgroundTag":"child-id-generation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}