{"record":{"id":"142bd25712a5e50b","repo":"gastownhall/beads","slug":"db-childcountersqlrepository-nextchildid-rows","errorCode":null,"errorMessage":"db: ChildCounterSQLRepository.NextChildID: rows: %w","messagePattern":"db: ChildCounterSQLRepository\\.NextChildID: rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/child_counter.go","lineNumber":72,"sourceCode":"\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(`\n\t\tINSERT INTO %s (parent_id, last_child) VALUES (?, ?)\n\t\tON DUPLICATE KEY UPDATE last_child = ?\n\t`, counterTable), parentID, next, next); err != nil {\n\t\treturn \"\", fmt.Errorf(\"db: ChildCounterSQLRepository.NextChildID: upsert counter for %s: %w\", parentID, err)\n\t}\n\n\treturn fmt.Sprintf(\"%s.%d\", parentID, next), nil\n}\n\nfunc (r *childCounterSQLRepositoryImpl) parentIsActiveWisp(ctx context.Context, parentID string) (bool, error) {\n\tvar probe int\n\terr := r.runner.QueryRowContext(ctx, \"SELECT 1 FROM wisps WHERE id = ? LIMIT 1\", parentID).Scan(&probe)\n\tswitch {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/child_counter.go#L54-L90","documentation":"After iterating child IDs, NextChildID calls rows.Err() to surface any error that occurred during iteration (driver I/O, query canceled, connection lost). This error wraps that post-iteration check. It means the result stream from the child-id query failed partway, so the computed `lastChild` is unreliable and no child ID was produced.","triggerScenarios":"Calling NextChildID while the underlying connection breaks during rows iteration, the context is canceled (Ctrl-C, deadline exceeded), or the server kills the query mid-stream.","commonSituations":"Long-running scans over large issue tables hitting network timeouts; context deadline too short for big parents; server-side wait_timeout dropping idle connections.","solutions":["Check the wrapped driver error (errors.Unwrap) — context.DeadlineExceeded means increase timeout or optimize the child query.","Retry the operation; the upsert only happens after this check so a retry is safe.","Verify network stability between the app and the Dolt/MySQL server (timeouts, proxies).","If cancelations are intentional, use a longer context for NextChildID during bulk operations."],"exampleFix":"// before: bare context cancelled mid-iteration\nctx := context.Background()\n\n// after: give child-scan queries an explicit generous deadline\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()","handlingStrategy":"retry","validationCode":"if err := ctx.Err(); err != nil {\n    return fmt.Errorf(\"context already done before NextChildID: %w\", err)\n}","typeGuard":"func isIterationError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"NextChildID: rows:\")\n}","tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    id, err := repo.NextChildID(ctx, parentID, opts)\n    if err == nil { return id, nil }\n    if !isIterationError(err) || ctx.Err() != nil { return \"\", err }\n    time.Sleep(backoff(attempt))\n}","preventionTips":["Use generous timeouts for child-creation flows","Keep issues table size in check; archive old wisps","Monitor network health to the Dolt server"],"tags":["database","sql","rows-iteration","go"],"backgroundTag":"query-iteration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}