bug(#126): harvest_quarter падает psycopg.errors.AmbiguousParameter в INSERT nspd_quarter_dumps #243

Closed
opened 2026-05-17 05:39:41 +00:00 by lekss361 · 0 comments
Owner

Симптом

tasks.nspd_sync.harvest_quarter (backend/app/workers/tasks/nspd_sync.py) падает на INSERT в nspd_quarter_dumps:

psycopg.errors.AmbiguousParameter: could not determine data type of parameter $2
LINE 11:         CASE WHEN $2 IS NULL THEN NULL
                           ^

GlitchTip issues BACKEND-2/3/4/6/7/8..22/24/26/27/33/34 (≥15 событий с 2026-05-16 19:33 UTC, разные cad'ы: 66:41:0204016, 66:41:0303018, 66:41:0206025, 66:41:0001001, 66:41:0206030, 66:41:0603016).

Все WMS requests возвращают 200 OK — данные собираются успешно (zouit_count=7, total_features=10 в последнем event'е), но 0 строк закоммитилось в БД — именно поэтому nspd_quarter_dumps=0.

Root cause

В _UPSERT_SQL есть CASE WHEN без явного CAST:

VALUES (
    %(quarter_cad)s,
    CASE WHEN %(geom_json)s IS NULL THEN NULL
         ELSE ST_Multi(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(%(geom_json)s), 3857), 4326))
    END,
    CASE WHEN %(bbox_xmin)s IS NULL THEN NULL
         ELSE ST_MakeEnvelope(%(bbox_xmin)s, %(bbox_ymin)s, %(bbox_xmax)s, %(bbox_ymax)s, 3857)
    END,
    ...
)

psycopg3 не может вывести тип $2 (geom_json) внутри CASE WHEN x IS NULL THEN NULL потому что оба branch имеют разный сигнал (NULL литерал vs PostGIS geometry). PG требует явный CAST.

См. правило .claude/rules/backend.md: «В SQL text(...): всегда CAST(:name AS type) — НИКОГДА :name::type».

Fix

В backend/app/workers/tasks/nspd_sync.py _UPSERT_SQL или эквивалентном файле:

CASE WHEN CAST(%(geom_json)s AS text) IS NULL THEN NULL
     ELSE ST_Multi(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(CAST(%(geom_json)s AS text)), 3857), 4326))
END

Аналогично для bbox_xmin/ymin/xmax/ymaxCAST(... AS double precision).

Acceptance

  • apply_async tasks.nspd_sync.harvest_quarter("66:41:0204016", 66) без ошибки
  • SELECT count(*) FROM nspd_quarter_dumps > 0
  • harvest_quarter: failed to write error row errors исчезают из GlitchTip
  • Existing tests pass (если есть в test_nspd_sync.py)

Severity

🔴 P0harvest_quarter task полностью нерабочая ≥18 часов. Блокирует:

  • #126 (NSPD WMS grid sampling) — даже если grid fix будет сделан, UPSERT упадёт
  • #115 KILLER (Engineering connection points) — runtime пустой
  • #231 / #234 / #235 — все смежные QA баги

Также блокирует частично PR #240 G3 cad_zouit fallback (см. issue #243 — fallback не срабатывает потому что dumps вообще нет → make_empty_result рано).

Дополнительно

Возможно есть и второй bug "failed to write error row" — psycopg падает на этом же SQL и при попытке записать error row (issues BACKEND-3 «failed to write error row»). Нужен отдельный try/except + simpler INSERT для error path.

(QA discovery 2026-05-17 через GlitchTip — mcp__glitchtip__glitchtip_latest_event issueId=34, 22)

## Симптом `tasks.nspd_sync.harvest_quarter` (`backend/app/workers/tasks/nspd_sync.py`) падает на INSERT в `nspd_quarter_dumps`: ``` psycopg.errors.AmbiguousParameter: could not determine data type of parameter $2 LINE 11: CASE WHEN $2 IS NULL THEN NULL ^ ``` GlitchTip issues BACKEND-2/3/4/6/7/8..22/24/26/27/33/34 (≥15 событий с 2026-05-16 19:33 UTC, разные cad'ы: 66:41:0204016, 66:41:0303018, 66:41:0206025, 66:41:0001001, 66:41:0206030, 66:41:0603016). **Все WMS requests возвращают 200 OK** — данные собираются успешно (`zouit_count=7`, `total_features=10` в последнем event'е), но **0 строк закоммитилось в БД** — именно поэтому `nspd_quarter_dumps=0`. ## Root cause В `_UPSERT_SQL` есть CASE WHEN без явного CAST: ```sql VALUES ( %(quarter_cad)s, CASE WHEN %(geom_json)s IS NULL THEN NULL ELSE ST_Multi(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(%(geom_json)s), 3857), 4326)) END, CASE WHEN %(bbox_xmin)s IS NULL THEN NULL ELSE ST_MakeEnvelope(%(bbox_xmin)s, %(bbox_ymin)s, %(bbox_xmax)s, %(bbox_ymax)s, 3857) END, ... ) ``` psycopg3 не может вывести тип `$2` (`geom_json`) внутри `CASE WHEN x IS NULL THEN NULL` потому что оба branch имеют разный сигнал (NULL литерал vs PostGIS geometry). PG требует явный CAST. См. правило `.claude/rules/backend.md`: «В SQL `text(...)`: всегда `CAST(:name AS type)` — НИКОГДА `:name::type`». ## Fix В `backend/app/workers/tasks/nspd_sync.py` `_UPSERT_SQL` или эквивалентном файле: ```sql CASE WHEN CAST(%(geom_json)s AS text) IS NULL THEN NULL ELSE ST_Multi(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(CAST(%(geom_json)s AS text)), 3857), 4326)) END ``` Аналогично для `bbox_xmin/ymin/xmax/ymax` — `CAST(... AS double precision)`. ## Acceptance - [ ] `apply_async tasks.nspd_sync.harvest_quarter("66:41:0204016", 66)` без ошибки - [ ] `SELECT count(*) FROM nspd_quarter_dumps` > 0 - [ ] `harvest_quarter: failed to write error row` errors исчезают из GlitchTip - [ ] Existing tests pass (если есть в `test_nspd_sync.py`) ## Severity 🔴 **P0** — `harvest_quarter` task **полностью нерабочая** ≥18 часов. Блокирует: - #126 (NSPD WMS grid sampling) — даже если grid fix будет сделан, UPSERT упадёт - #115 KILLER (Engineering connection points) — runtime пустой - #231 / #234 / #235 — все смежные QA баги Также блокирует частично PR #240 G3 cad_zouit fallback (см. issue #243 — fallback не срабатывает потому что dumps вообще нет → make_empty_result рано). ## Дополнительно Возможно есть и второй bug "failed to write error row" — psycopg падает на этом же SQL и при попытке записать error row (issues BACKEND-3 «failed to write error row»). Нужен отдельный try/except + simpler INSERT для error path. (QA discovery 2026-05-17 через GlitchTip — `mcp__glitchtip__glitchtip_latest_event` issueId=34, 22)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#243
No description provided.