{"record":{"id":"29eb5627ac06ee4c","repo":"gastownhall/beads","slug":"get-dependents-from-s-w","errorCode":null,"errorMessage":"get dependents from %s: %w","messagePattern":"get dependents from (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":1173,"sourceCode":"\treturn results, nil\n}\n\n// GetDependentsWithMetadataInTx returns issues that depend on the given issueID\n// along with the dependency type. Works within an existing transaction.\n//\n//nolint:gosec // G201: table names come from WispTableRouting (hardcoded constants)\nfunc GetDependentsWithMetadataInTx(ctx context.Context, tx DBTX, issueID string) ([]*types.IssueWithDependencyMetadata, error) {\n\ttype depMeta struct {\n\t\tdepID, depType string\n\t}\n\n\t// Query both dependency tables to find all dependents.\n\tvar deps []depMeta\n\tfor _, depTable := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\trows, err := tx.QueryContext(ctx, fmt.Sprintf(\n\t\t\t`SELECT issue_id, type FROM %s WHERE %s = ?`, depTable, DepTargetExpr), issueID)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"get dependents from %s: %w\", depTable, err)\n\t\t}\n\t\tfor rows.Next() {\n\t\t\tvar d depMeta\n\t\t\tif scanErr := rows.Scan(&d.depID, &d.depType); scanErr != nil {\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn nil, fmt.Errorf(\"get dependents: scan: %w\", scanErr)\n\t\t\t}\n\t\t\tdeps = append(deps, d)\n\t\t}\n\t\t_ = rows.Close()\n\t\tif err := rows.Err(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"get dependents: rows from %s: %w\", depTable, err)\n\t\t}\n\t}\n\n\tif len(deps) == 0 {\n\t\treturn nil, nil\n\t}","sourceCodeStart":1155,"sourceCodeEnd":1191,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L1155-L1191","documentation":"GetDependentsWithMetadataInTx wraps the error from tx.QueryContext when the initial SELECT of dependent rows fails against one of the dependency tables (\"dependencies\" or \"wisp_dependencies\", named in the message). This is a query-execution failure, not a row-scan failure: the SQL never returned a usable row set.","triggerScenarios":"Calling GetDependentsWithMetadataInTx (via buildDependencyTreeInTx or ExecuteRelated) when the SELECT issue_id, type FROM <table> WHERE <target> = ? statement fails — missing table, bad connection, syntax/permission error, or cancelled context.","commonSituations":"Running against a database migrated from an older version where wisp_dependencies doesn't exist yet; insufficient privileges on one table; dead connection pool after idle timeout; schema drift between environments.","solutions":["Run the failing SELECT manually against the named table to reproduce the driver error.","Verify both dependencies and wisp_dependencies tables exist and are migrated to the current schema version.","Check DB user permissions on both dependency tables.","Check connection health and context deadline; reconnect/retry if the error is transient."],"exampleFix":"// before: partial migration, wisp table missing\n// after: ensure migrations run before storage use\nif err := migrations.Apply(ctx, db); err != nil { return err }\ndeps, err := GetDependentsWithMetadataInTx(ctx, tx, issueID)","handlingStrategy":"validation","validationCode":"// Verify both dependency tables exist before querying dependents\nvar n int\nfor _, t := range []string{\"dependencies\", \"wisp_dependencies\"} {\n    err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?`, t).Scan(&n)\n    if err != nil || n == 0 { return fmt.Errorf(\"table %s missing; run migrations\", t) }\n}","typeGuard":"func isQueryExecErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"from dependencies\") || strings.Contains(err.Error(), \"from wisp_dependencies\")\n}","tryCatchPattern":"deps, err := GetDependentsWithMetadataInTx(ctx, tx, issueID)\nif err != nil {\n    var mysqlErr *mysql.MySQLError\n    if errors.As(err, &mysqlErr) && mysqlErr.Number == 1146 {\n        return fmt.Errorf(\"schema not migrated: %w\", err)\n    }\n    return err\n}","preventionTips":["Run schema migrations at startup before any storage calls.","Verify DB grants cover both dependencies and wisp_dependencies.","Ping the connection/pool before long transactions.","Keep dev/staging/prod schemas version-aligned."],"tags":["database","sql","go","query-execution"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}