{"record":{"id":"e96487f1d80f22ca","repo":"gastownhall/beads","slug":"db-rawsql-query-scan-w","errorCode":null,"errorMessage":"db: RawSQL Query: scan: %w","messagePattern":"db: RawSQL Query: scan: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/raw_sql.go","lineNumber":40,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: %w\", err)\n\t}\n\tdefer rows.Close()\n\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: columns: %w\", err)\n\t}\n\n\tresult := &domain.RawSQLResult{Columns: columns}\n\tfor rows.Next() {\n\t\tvalues := make([]any, len(columns))\n\t\tptrs := make([]any, len(columns))\n\t\tfor i := range values {\n\t\t\tptrs[i] = &values[i]\n\t\t}\n\t\tif err := rows.Scan(ptrs...); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: scan: %w\", err)\n\t\t}\n\t\tfor i, v := range values {\n\t\t\tif b, ok := v.([]byte); ok {\n\t\t\t\tvalues[i] = string(b)\n\t\t\t}\n\t\t}\n\t\tresult.Rows = append(result.Rows, values)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: rows: %w\", err)\n\t}\n\treturn result, nil\n}\n\nfunc (r *rawSQLRepositoryImpl) Exec(ctx context.Context, query string, args ...any) (int64, error) {\n\tres, err := r.runner.ExecContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"db: RawSQL Exec: %w\", err)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/raw_sql.go#L22-L58","documentation":"This error wraps a failure from sql.Rows.Scan inside RawSQLRepository.Query. Query scans each result row into a slice of `any` pointers sized to the column count; Scan fails when a driver value cannot be converted into the destination. Because destinations are `*any`, failures are almost always driver-level conversion or connection errors rather than type mismatches.","triggerScenarios":"Calling RawSQLRepository.Query with a query whose driver returns values the sql package cannot scan (e.g. unsupported column types, corrupt/invalid cell data, or a connection dropped mid-result-set).","commonSituations":"Running raw SQL against Dolt/MySQL with exotic column types (JSON, GEOMETRY) the driver struggles with; stale/canceled connections mid-iteration; context cancellation while the driver materializes a row.","solutions":["Check the wrapped driver error (%w) to identify the offending column/type","Cast problematic columns in SQL (e.g. CAST(col AS CHAR) or JSON_EXTRACT) so the driver returns strings","Retry the query if the cause was a transient connection drop","Upgrade the database driver to a version with broader type conversion support"],"exampleFix":"// before: SELECT meta FROM issues WHERE id = ?  (meta is JSON)\n// after:  SELECT CAST(meta AS CHAR) FROM issues WHERE id = ?","handlingStrategy":"try-catch","validationCode":"// ensure connection is alive before querying\nif err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"db unavailable: %w\", err) }","typeGuard":"func isScanError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"RawSQL Query: scan\")\n}","tryCatchPattern":"res, err := repo.Query(ctx, q, args...)\nif err != nil {\n\tif isScanError(err) {\n\t\t// rewrite query with CASTs for exotic column types, then retry once\n\t}\n\treturn err\n}","preventionTips":["CAST exotic column types (JSON, BLOB) to CHAR in raw SQL","Keep queries bounded with LIMIT to avoid mid-stream drops","Ping or health-check the DB before long raw queries","Keep the driver up to date"],"tags":["database","sql","scan","raw-sql"],"backgroundTag":"sql-row-scan-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}