{"record":{"id":"2e96f04c8985e987","repo":"gastownhall/beads","slug":"get-dependent-records-from-s-w","errorCode":null,"errorMessage":"get dependent records from %s: %w","messagePattern":"get dependent records from (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependency_queries.go","lineNumber":195,"sourceCode":"func getDependentRecordsIntoFromTable(ctx context.Context, tx DBTX, depTable string, targetIDs []string, seen map[string]bool, result map[string][]*types.Dependency) error {\n\tfor start := 0; start < len(targetIDs); start += queryBatchSize {\n\t\tend := start + queryBatchSize\n\t\tif end > len(targetIDs) {\n\t\t\tend = len(targetIDs)\n\t\t}\n\t\tbatch := targetIDs[start:end]\n\t\tplaceholders := make([]string, len(batch))\n\t\targs := make([]any, len(batch))\n\t\tfor i, id := range batch {\n\t\t\tplaceholders[i] = \"?\"\n\t\t\targs[i] = id\n\t\t}\n\t\trows, err := tx.QueryContext(ctx, fmt.Sprintf(\n\t\t\t`SELECT id, issue_id, %s AS depends_on_id, type, created_at, created_by, metadata, thread_id\n\t\t\t FROM %s WHERE %s ORDER BY %s`,\n\t\t\tDepTargetExpr, depTable, depTargetIn(\"\", strings.Join(placeholders, \",\")), DepTargetExpr), args...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"get dependent records from %s: %w\", depTable, err)\n\t\t}\n\t\tfor rows.Next() {\n\t\t\tdep, scanErr := scanDependentRow(rows)\n\t\t\tif scanErr != nil {\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn fmt.Errorf(\"get dependent records: scan: %w\", scanErr)\n\t\t\t}\n\t\t\t// De-dup by row id (depid): the wisp copy of a promoted edge carries\n\t\t\t// the same id as the durable copy scanned first, so skip the repeat.\n\t\t\tif seen[dep.ID] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tseen[dep.ID] = true\n\t\t\tresult[dep.DependsOnID] = append(result[dep.DependsOnID], dep)\n\t\t}\n\t\t_ = rows.Close()\n\t\tif err := rows.Err(); err != nil {\n\t\t\treturn fmt.Errorf(\"get dependent records: rows: %w\", err)","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependency_queries.go#L177-L213","documentation":"This error wraps the failure of the QueryContext call that reads dependent (inbound) dependency rows from either the 'dependencies' or 'wisp_dependencies' table inside getDependentRecordsIntoFromTable. It is thrown when the database rejects or cannot execute the SELECT (bad SQL, missing table, connection/context failure). The wrapped %s names which dependency table failed, and %w preserves the underlying driver error.","triggerScenarios":"Calling GetDependentRecordsForIssuesInTx when the target dependency table does not exist (unmigrated database), the SQL fails (e.g. driver-specific syntax issue with DepTargetExpr), the context is canceled, or the connection to the database drops mid-query.","commonSituations":"Running a new binary against an old database missing wisp_dependencies; a corrupted or partially-migrated Dolt/SQLite schema; network interruption to a remote database; context timeout during a large batched read.","solutions":["Check the wrapped driver error to identify the root cause (table missing vs connection vs syntax).","Run schema migrations so both dependencies and wisp_dependencies exist (bd should create them; verify with a schema dump).","If wisp_dependencies is legitimately absent in your deployment, the caller already tolerates isTableNotExistError for the optional table — verify the table-exists detection matches your driver's error string.","Retry the operation if the wrapped error is transient (connection reset, context deadline); otherwise fix the environment.","Upgrade or downgrade to matching storage-schema versions of the binary."],"exampleFix":"// before (caller sees opaque failure)\ndeps, err := GetDependentRecordsForIssuesInTx(ctx, tx, ids)\nif err != nil { log.Fatal(err) }\n// after (distinguish missing-table from real failure)\ndeps, err := GetDependentRecordsForIssuesInTx(ctx, tx, ids)\nif err != nil {\n    if isTableNotExistError(err) { /* run migrations */ }\n    log.Fatalf(\"dependent records read failed: %v\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: verify tables exist before the call\nvar one int\nif err := tx.QueryRowContext(ctx, \"SELECT 1 FROM wisp_dependencies LIMIT 1\").Scan(&one); err != nil && !isTableNotExistError(err) {\n    return fmt.Errorf(\"wisp_dependencies unavailable: %w\", err)\n}","typeGuard":"func isDependencyTableReady(ctx context.Context, tx DBTX, table string) bool {\n    var one int\n    err := tx.QueryRowContext(ctx, \"SELECT 1 FROM \"+table+\" LIMIT 1\").Scan(&one)\n    return err == nil || isTableNotExistError(err)\n}","tryCatchPattern":"deps, err := GetDependentRecordsForIssuesInTx(ctx, tx, targetIDs)\nif err != nil {\n    var tblErr *TableNotExistError\n    if errors.As(err, &tblErr) || isTableNotExistError(err) {\n        // optional table path: degrade gracefully\n    } else if isTransientNetError(err) {\n        // retry with backoff\n    } else {\n        return err\n    }\n}","preventionTips":["Keep schema migrations running before every binary upgrade","Pass contexts with realistic deadlines for batched reads","Monitor connection health (timeouts, keepalives) on remote databases","Verify DB user grants cover both dependency tables"],"tags":["database","sql","storage","dependency-graph"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}