fix: cover_templates config double-encoded JSON causing 500 #1363

Merged
xiaoxia merged 2 commits from fix/cover-templates-double-encoded-config into develop 2026-08-13 23:55:40 +08:00
Owner

Problem

GET /api/v1/cover-templates returns 500 Internal Server Error.

Root cause: Migration 055 seed data used json.dumps(config) which double-serialized the config dict.

SQLAlchemy JSON column already handles serialization automatically. json.dumps() turned dicts into strings first, then the JSON column serialized them again, resulting in JSON string scalars stored in the database:

{} (dict) -> json.dumps() -> "{}" (str) -> JSON column -> {} (JSON string)

When Pydantic CoverTemplateResponse reads this, config is a string "{}" instead of a dict {}, causing ValidationError -> 500.

Fix

  1. migration 055: remove json.dumps(), pass dict directly to SQLAlchemy JSON column
  2. migration 056: fix existing data - extract text from JSON string scalar, cast back to JSON object

Database fix already applied

The data fix has been manually applied to staging. This PR ensures consistency for future deployments.

## Problem `GET /api/v1/cover-templates` returns 500 Internal Server Error. **Root cause**: Migration 055 seed data used `json.dumps(config)` which double-serialized the config dict. SQLAlchemy `JSON` column already handles serialization automatically. `json.dumps()` turned dicts into strings first, then the JSON column serialized them again, resulting in JSON string scalars stored in the database: ``` {} (dict) -> json.dumps() -> "{}" (str) -> JSON column -> {} (JSON string) ``` When Pydantic `CoverTemplateResponse` reads this, `config` is a string `"{}"` instead of a dict `{}`, causing `ValidationError` -> 500. ## Fix 1. **migration 055**: remove `json.dumps()`, pass dict directly to SQLAlchemy JSON column 2. **migration 056**: fix existing data - extract text from JSON string scalar, cast back to JSON object ## Database fix already applied The data fix has been manually applied to staging. This PR ensures consistency for future deployments.
xiaoxia added 1 commit 2026-08-13 23:30:49 +08:00
fix: cover_templates config double-encoded JSON causing 500
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 37s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m45s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m33s
AI Code Review / AI Code Review (pull_request) Successful in 2m47s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m52s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 4m23s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m23s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 5m15s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
fdfe955a0f
Root cause: migration 055 seed data used json.dumps(config) which
double-serialized the config dict. SQLAlchemy JSON column already
handles serialization, so json.dumps() turned dicts into strings,
then JSON column serialized them again into JSON string scalars.

Example: {} -> json.dumps -> "{}" -> JSON column -> "\"{}\""
When Pydantic CoverTemplateResponse reads this, it gets a string
instead of a dict, causing ValidationError -> 500.

Fix:
1. migration 055: remove json.dumps(), pass dict directly
2. migration 056: fix existing data by extracting text from JSON
   string scalar and casting back to JSON object

🚀 预览环境已部署

项目 详情
PR号 #1363
预览链接 https://pr-1363.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1363 | | 预览链接 | [https://pr-1363.preview.xiaoxiajianji.com](https://pr-1363.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot added 1 commit 2026-08-13 23:36:05 +08:00
style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 31s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m49s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m17s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m20s
AI Code Review / AI Code Review (pull_request) Failing after 2m40s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m31s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 4m29s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m30s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m45s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m33s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m17s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 44s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 48s
69edceb2f0
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:是
  • 阻塞级问题数量:1 个

📊 审查概览

  • 整体评价:需修改
  • 建议级问题数量:0 个

🔴 阻塞级问题(必须修复)

  1. [056_fix_cover_templates_config.py: 28] 数据库兼容性缺失导致数据损坏风险
    • 问题类型:数据损坏风险 / 逻辑Bug
    • 问题描述:修复脚本 056 仅针对 postgresql 方言进行了处理(if conn.dialect.name == "postgresql":)。如果项目支持 MySQL 或 SQLite 等其他数据库,由 055(旧版本)引起的双重序列化问题将无法被修复。这会导致在这些数据库上,config 字段依然保持为 JSON 字符串(如 "{}")而非 JSON 对象(如 {}),从而引发应用层(如 Pydantic 模型)校验失败或运行时错误。
    • 修改建议:
      1. 如果项目仅支持 PostgreSQL,请在代码中添加显式断言(如 assert conn.dialect.name == "postgresql")以防止在非 PG 环境下静默跳过修复。
      2. 如果项目支持多数据库,必须补充 MySQL 等数据库的修复逻辑。例如 MySQL 可以使用 JSON_UNQUOTE(JSON_EXTRACT(config, '$')) 或类似的逻辑来处理转义。

💡 改进建议(不阻塞合并)

良好实践

  1. 055_cover_templates.py:正确移除了 json.dumps,利用 SQLAlchemy 的 JSON 类型自动处理序列化,避免了手动序列化导致的类型错误。
  2. 056_fix_cover_templates_config.py:PostgreSQL 的修复逻辑使用了 jsonb_typeof#>> 操作符,准确地识别并修复了被双重序列化的字符串数据,逻辑针对性强。

🤖 由 AI 代码审查机器人自动生成 | 2026-08-13 15:38:46 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:1 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:0 个 ### 🔴 阻塞级问题(必须修复) 1. **[056_fix_cover_templates_config.py: 28] 数据库兼容性缺失导致数据损坏风险** - 问题类型:数据损坏风险 / 逻辑Bug - 问题描述:修复脚本 `056` 仅针对 `postgresql` 方言进行了处理(`if conn.dialect.name == "postgresql":`)。如果项目支持 MySQL 或 SQLite 等其他数据库,由 `055`(旧版本)引起的双重序列化问题将无法被修复。这会导致在这些数据库上,`config` 字段依然保持为 JSON 字符串(如 `"{}"`)而非 JSON 对象(如 `{}`),从而引发应用层(如 Pydantic 模型)校验失败或运行时错误。 - 修改建议: 1. 如果项目仅支持 PostgreSQL,请在代码中添加显式断言(如 `assert conn.dialect.name == "postgresql"`)以防止在非 PG 环境下静默跳过修复。 2. 如果项目支持多数据库,必须补充 MySQL 等数据库的修复逻辑。例如 MySQL 可以使用 `JSON_UNQUOTE(JSON_EXTRACT(config, '$'))` 或类似的逻辑来处理转义。 ### 💡 改进建议(不阻塞合并) 无 ### ✅ 良好实践 1. **055_cover_templates.py**:正确移除了 `json.dumps`,利用 SQLAlchemy 的 `JSON` 类型自动处理序列化,避免了手动序列化导致的类型错误。 2. **056_fix_cover_templates_config.py**:PostgreSQL 的修复逻辑使用了 `jsonb_typeof` 和 `#>>` 操作符,准确地识别并修复了被双重序列化的字符串数据,逻辑针对性强。 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-13 15:38:46 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
auto-approve-bot approved these changes 2026-08-13 23:45:30 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-08-13 23:45:30 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
xiaoxia merged commit 6a4085452d into develop 2026-08-13 23:55:40 +08:00

🗑️ 预览环境已清理

PR #1363 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1363 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.