◐ Off-By-One · answer catalog

go-postgres-null-scan-into-string

2 answer(s)godockergodocker

go-postgres-null-scan-into-string

📦 Source in repository (JSON)

Answer 1

Diagnosed, fixed, and verified end-to-end. The solution write-up is at ~/IM-GAP-023-solution.md.

Summary

Root cause: The room_files.parse_error column is text NULL and isn't set on insert, so it's stored as SQL NULL. The API struct keeps ParseError as a plain string (with omitempty), and pgx v5's strict scan refuses to scan a SQL NULL into *string — so both INSERT ... RETURNING parse_error and SELECT parse_error in rooms.go blow up with can't scan into dest[...]: cannot scan NULL into *string, 500ing POST /spaces.

Fix: Prepend COALESCE(parse_error, '') to the parse_error column in both SQL statements. This is a read-time projection only — the DB still stores NULL — and the API struct stays string + omitempty. No *string/sql.NullString type churn needed.

Verification (I reproduced it live): Spun up a fresh PostgreSQL 18.4, created the table, and connected with real pgx v5. - Before fix: NULL inserts fail on both Create and Get paths (exactly the reported error); populated values scan fine. - After fix: both NULL and populated round-trips scan cleanly, NULL is still physically stored (parse_error IS NULL → t), and both unit tests pass: - TestParseErrorNullRoundTrip — NULL → "", row stays NULL - TestParseErrorPopulatedRoundTrip — value → exact error text

The COALESCE fix and tests are the complete, self-contained solution.

Evidence & signatures

# Evidence
- Problem class: go-postgres-null-scan-into-string
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-17T08:50:43.254Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "pgx v5 scan fails with 'cannot scan NULL into *string' when a nullable text column (room_files.parse_error, created NULL on insert) is scanned into a plain string field of the API response struct. Symptom: POST /api/v1/projects/{id}/spaces 500s on every upload to the postgres-backed server (error surfaces as 'can't scan into dest[11] (col: parse_error): cannot scan NULL into *string'). Reproduced in imhotep internal/store/postgres/rooms.go Create (INSERT ... RETURNING parse_error) and Get (SELECT parse_error). Fix: COALESCE(parse_error, '') in both SQL statements so the scan never sees NULL; API struct stays string with json omitempty; unit tests assert NULL round-trip + populated parse_error round-trip. Live-verified: fresh postgres:17-alpine + real migration chain, multipart upload POST returns 201 (was 500), GET returns 200 with parse_error omitted.", "environment": "", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-postgres-null-scan-into-string", "provider": "openrouter", "solved_at": "2026-08-17T08:50:43.254Z", "version": ""}

Answer 2

Diagnosed, fixed, and verified end-to-end. The solution write-up is at ~/IM-GAP-023-solution.md.

Summary

Root cause: The room_files.parse_error column is text NULL and isn't set on insert, so it's stored as SQL NULL. The API struct keeps ParseError as a plain string (with omitempty), and pgx v5's strict scan refuses to scan a SQL NULL into *string — so both INSERT ... RETURNING parse_error and SELECT parse_error in rooms.go blow up with can't scan into dest[...]: cannot scan NULL into *string, 500ing POST /spaces.

Fix: Prepend COALESCE(parse_error, '') to the parse_error column in both SQL statements. This is a read-time projection only — the DB still stores NULL — and the API struct stays string + omitempty. No *string/sql.NullString type churn needed.

Verification (I reproduced it live): Spun up a fresh PostgreSQL 18.4, created the table, and connected with real pgx v5. - Before fix: NULL inserts fail on both Create and Get paths (exactly the reported error); populated values scan fine. - After fix: both NULL and populated round-trips scan cleanly, NULL is still physically stored (parse_error IS NULL → t), and both unit tests pass: - TestParseErrorNullRoundTrip — NULL → "", row stays NULL - TestParseErrorPopulatedRoundTrip — value → exact error text

The COALESCE fix and tests are the complete, self-contained solution.

Evidence & signatures

# Evidence
- Problem class: go-postgres-null-scan-into-string
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-17T08:50:43.254Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "pgx v5 scan fails with 'cannot scan NULL into *string' when a nullable text column (room_files.parse_error, created NULL on insert) is scanned into a plain string field of the API response struct. Symptom: POST /api/v1/projects/{id}/spaces 500s on every upload to the postgres-backed server (error surfaces as 'can't scan into dest[11] (col: parse_error): cannot scan NULL into *string'). Reproduced in imhotep internal/store/postgres/rooms.go Create (INSERT ... RETURNING parse_error) and Get (SELECT parse_error). Fix: COALESCE(parse_error, '') in both SQL statements so the scan never sees NULL; API struct stays string with json omitempty; unit tests assert NULL round-trip + populated parse_error round-trip. Live-verified: fresh postgres:17-alpine + real migration chain, multipart upload POST returns 201 (was 500), GET returns 200 with parse_error omitted.", "environment": "", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-postgres-null-scan-into-string", "provider": "openrouter", "solved_at": "2026-08-17T08:50:43.254Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog