{"record":{"id":"0714938d14782dad","repo":"gastownhall/beads","slug":"failed-to-batch-fetch-child-statuses-from-s-w","errorCode":null,"errorMessage":"failed to batch-fetch child statuses from %s: %w","messagePattern":"failed to batch-fetch child statuses from (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/epic_closure.go","lineNumber":92,"sourceCode":"\tchildStatusMap := make(map[string]string)\n\tif len(allChildIDs) > 0 {\n\t\t// Check both issues and wisps tables for child statuses (bd-w2w)\n\t\tfor _, table := range []string{\"issues\", \"wisps\"} {\n\t\t\tfor start := 0; start < len(allChildIDs); start += queryBatchSize {\n\t\t\t\tend := start + queryBatchSize\n\t\t\t\tif end > len(allChildIDs) {\n\t\t\t\t\tend = len(allChildIDs)\n\t\t\t\t}\n\t\t\t\tbatch := allChildIDs[start:end]\n\t\t\t\tplaceholders, args := buildSQLInClause(batch)\n\n\t\t\t\tstatusQuery := fmt.Sprintf(\"SELECT id, status FROM %s WHERE id IN (%s)\", table, placeholders)\n\t\t\t\tstatusRows, err := tx.QueryContext(ctx, statusQuery, args...)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif isTableNotExistError(err) {\n\t\t\t\t\t\tbreak // wisps table may not exist on pre-migration databases\n\t\t\t\t\t}\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to batch-fetch child statuses from %s: %w\", table, err)\n\t\t\t\t}\n\t\t\t\tfor statusRows.Next() {\n\t\t\t\t\tvar id, status string\n\t\t\t\t\tif err := statusRows.Scan(&id, &status); err != nil {\n\t\t\t\t\t\tstatusRows.Close()\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"scan child status: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tchildStatusMap[id] = status\n\t\t\t\t}\n\t\t\t\tstatusRows.Close()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Step 4: Batch-fetch all epic issues\n\tepicsWithChildren := make([]string, 0)\n\tfor _, epicID := range epicIDs {\n\t\tif len(epicChildMap[epicID]) > 0 {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/epic_closure.go#L74-L110","documentation":"To decide closure eligibility, the function batch-fetches child issue statuses with `SELECT id, status FROM <table> WHERE id IN (...)`. A query failure on a table that exists (the not-exist case is tolerated for wisps) is wrapped with this message and the table name. It means child statuses could not be loaded, so epics cannot be safely evaluated for closure.","triggerScenarios":"Calling GetEpicsEligibleForClosureInTx when the batched status query errors — too many placeholders/args overflow on huge child sets, connection failure, or missing status column.","commonSituations":"Very large epics producing SQL statements that exceed driver parameter limits; Dolt server restarts mid-command; schema drift removing the status column.","solutions":["Read the table name and wrapped cause; verify the table has `id` and `status` columns.","Retry — transient connection errors usually clear.","If parameter limits are the cause, split work into smaller batches or chunk epics.","Run migrations to fix schema drift."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if len(childIDs) > 500 { return errors.New(\"child set too large; chunk before closure analysis\") }\nif err := db.PingContext(ctx); err != nil { return err }","typeGuard":"func isStatusFetchErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to batch-fetch child statuses from\")\n}","tryCatchPattern":"epics, err := GetEpicsEligibleForClosureInTx(ctx, tx)\nif err != nil {\n    if isStatusFetchErr(err) && errors.Is(err, driver.ErrBadConn) {\n        return retry(ctx, epics)\n    }\n    return err\n}","preventionTips":["Chunk very large child ID sets instead of one giant IN clause.","Keep connection pools healthy for long batch operations.","Run migrations so status columns match expectations.","Schedule closure jobs during low write traffic."],"tags":["go","sql","storage","query"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}