Skip to content

fix(console): 修复 workspaces API 在 schema 漂移时的静默 500 - #119

Open
Postroggy wants to merge 4 commits into
superduck-ai:mainfrom
Postroggy:fix/console-schema-drift-resilience
Open

fix(console): 修复 workspaces API 在 schema 漂移时的静默 500#119
Postroggy wants to merge 4 commits into
superduck-ai:mainfrom
Postroggy:fix/console-schema-drift-resilience

Conversation

@Postroggy

@Postroggy Postroggy commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #118.

摘要

本地 dev 环境 GET /api/console/organizations/{org}/workspaces 在 workspaces 表缺 data_residency 列(历史 schema 漂移)时返回 500,连锁打挂 console 前端工作空间上下文(memory store 详情页进不去、列表行点击无反应)。本 PR 修复两个根因:

  1. DB 层isUndefinedTableError 只识别 PG 42P01(undefined_table),不识别 42703(undefined_column)。新增 isUndefinedRelationError 覆盖两者,7 处 console 列表查询(workspaces / api_keys / invites / members / admin_requests)切到新 helper,让列缺失与表缺失一样降级返回空列表。
  2. handler 层internalError 吞掉原始 err。新增 internalErrorWithCause(log err + request_id 再 500),接入 handleListConsoleWorkspaces

详见 #118

改动

  • internal/db/postgres_errors.go:新增 isUndefinedRelationError + 两个 PG code 常量
  • internal/db/console_api_keys.go:删除旧 isUndefinedTableError + unused pgconn import,3 处调用切到新 helper
  • internal/db/console_invites.go / console_members.go / admin_requests.go:调用切到新 helper
  • internal/platformapi/support.go:新增 internalErrorWithCause
  • internal/platformapi/console_api_keys.gohandleListConsoleWorkspaces err 路径改用 internalErrorWithCause

验证

  • go build ./...
  • golangci-lint run --config .golangci.yml ./internal/db/... ./internal/platformapi/... ✅ 0 issues
  • just dead-code
  • just duplicates
  • just complexity
  • go test ./internal/db/... ./internal/platformapi/...
  • 手动复现:ALTER TABLE workspaces DROP COLUMN data_residency → 修复前 500;修复后 200 空列表 + 后端 log 记录 undefined_column

设计文档

本次只改错误处理兜底逻辑,不涉及公开 API、数据模型、状态机或架构边界变更。docs/design/ 无需更新。

不在本 PR 范围

  • 其余 48 处 internalError 吞 err:internalErrorWithCause 已提供入口,后续可逐步推广,不强制本 PR 全改
  • 本地 DB schema 漂移根治(建议重建 dev DB)
  • .golangci.yml 未排除 web/node_modules 的 flatted 误报(与本 PR 无关)

Summary by CodeRabbit

  • Bug Fixes
    • Improved resilience when expected data structures are unavailable, allowing affected lists to load as empty instead of failing.
    • Preserved proper error handling for unexpected database failures.
    • Improved diagnostic details for workspace listing errors while maintaining a user-friendly server error response.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Postroggy, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f1413f7-9d22-470d-8787-c2c2396c2efd

📥 Commits

Reviewing files that changed from the base of the PR and between 3f3f61d and fede351.

📒 Files selected for processing (8)
  • internal/api/server.go
  • internal/db/admin_requests.go
  • internal/db/console_api_keys.go
  • internal/db/console_invites.go
  • internal/db/console_members.go
  • internal/db/postgres_errors.go
  • internal/platformapi/console_api_keys.go
  • internal/platformapi/platform_backend_routes.go
📝 Walkthrough

Walkthrough

Changes

Schema drift handling

Layer / File(s) Summary
Database error classification and query fallbacks
internal/db/postgres_errors.go, internal/db/*
Undefined-table and undefined-column PostgreSQL errors now share the undefined-relation fallback across affected queries.
Workspace API error diagnostics
internal/platformapi/support.go, internal/platformapi/console_api_keys.go
Workspace listing failures are logged with the underlying error and request ID before returning HTTP 500.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: arthur-zhang

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 7 处 console 列表查询已改为在 42P01/42703 下降级返回空列表,并补充了带错误原因的 500 记录。
Out of Scope Changes check ✅ Passed 改动都围绕 schema 漂移兜底与错误可诊断展开,未见明显无关变更。
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次修复的核心问题:workspaces API 在 schema 漂移时出现静默 500。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Postroggy
Postroggy marked this pull request as ready for review July 19, 2026 05:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/platformapi/support.go`:
- Around line 178-186: Update both internalError and internalErrorWithCause in
support.go to use httpapi.WriteError for their 500 responses instead of
writeJSON, preserving the existing message and status while returning the
Anthropic-compatible error envelope. Keep internalErrorWithCause’s slog.Error
logging and request ID handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ac583313-720f-4560-a916-9b22f57beb6b

📥 Commits

Reviewing files that changed from the base of the PR and between e209f2d and 3f3f61d.

📒 Files selected for processing (7)
  • internal/db/admin_requests.go
  • internal/db/console_api_keys.go
  • internal/db/console_invites.go
  • internal/db/console_members.go
  • internal/db/postgres_errors.go
  • internal/platformapi/console_api_keys.go
  • internal/platformapi/support.go

Comment thread internal/platformapi/support.go

@duckpr duckpr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DuckPR reviewer: opencode
Model: anthropic/glm-5.2

ℹ️ 没有严重问题 — 行内有几处小建议。

Reviewed changes — 修复 console 工作区 API 在 schema 漂移时返回静默 500:DB 层将 undefined_table / undefined_column 统一降级为空列表,handler 层在 500 前记录原始错误与 request_id

  • internal/db/postgres_errors.go 新增 isUndefinedRelationError,同时识别 PG 错误码 42P0142703
  • 将 7 处 console 查询(admin_requestsconsole_api_keysconsole_invitesconsole_membersconsole_api_keys.CountConsoleAPIKeys)从 isUndefinedTableError 切换到 isUndefinedRelationError
  • internal/platformapi/support.go 新增 internalErrorWithCause,先记录错误与 request_id 再返回 500。
  • handleListConsoleWorkspaces 改用 internalErrorWithCause,其余 handler 的 internalError 调用保持现状。

ℹ️ Nitpicks

  • 建议为 isUndefinedRelationError 补充单元测试,覆盖 42P01 / 42703 / 其他错误 / nil 四种情况;pgconn.PgError 可以直接构造,无需真实数据库。

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using anthropic/glm-5.2𝕏

Comment thread internal/db/postgres_errors.go Outdated
Comment thread internal/platformapi/support.go Outdated
@Postroggy Postroggy changed the title [Console] 修复 workspaces API 在 schema 漂移时的静默 500 fix(console): 修复 workspaces API 在 schema 漂移时的静默 500 Jul 19, 2026
The console workspace list query selects data_residency from the
workspaces table, but isUndefinedTableError only swallowed PG code
42P01 (undefined_table). A drifted dev database missing the column
surfaced as 42703 (undefined_column), which escaped the guard and
returned 500 from GET /api/console/organizations/{org}/workspaces.
That 500 cascaded through the console workspace context and broke
navigation into memory store detail pages.

- Add isUndefinedRelationError in internal/db/postgres_errors.go
  covering both 42P01 and 42703, and switch the seven console list
  queries that used isUndefinedTableError to the broader helper.
- Add internalErrorWithCause in internal/platformapi/support.go that
  logs the underlying error and request id before responding 500, and
  use it in handleListConsoleWorkspaces so future failures stay
  diagnosable instead of a bare "failed to list workspaces".

Schema drift now degrades to an empty list with a logged cause,
matching the existing undefined_table behaviour.
- internal/api/server.go: Server 新增 logger 字段,注入到 RegisterConsoleOrganizationWorkspaceRoutes
- internal/platformapi/platform_backend_routes.go: 注册函数新增 logger 参数
- internal/platformapi/console_api_keys.go: handleListConsoleWorkspaces 新增 logger 参数并传递给 internalErrorWithCause
- internal/platformapi/support.go: internalErrorWithCause 改用参数传入的 logger(nil 时 fallback slog.Default())
- internal/db/postgres_errors.go: isUndefinedRelationError 注释覆盖写操作场景
@Postroggy
Postroggy force-pushed the fix/console-schema-drift-resilience branch from d107c54 to 3d16dd5 Compare July 26, 2026 14:27

@duckpr duckpr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DuckPR reviewer: opencode
Model: anthropic/glm-5.2

✅ No new issues found. Both prior nits are addressed cleanly in 3d16dd5.

Reviewed changes — 回应上一轮 review 的两条 nit:将 internalErrorWithCause 的日志改用注入的 logger,并修正 isUndefinedRelationError 的注释范围以覆盖读路径与 RemoveOrgUser 写路径。

  • internal/api/server.goServer 新增 logger 字段(取自 ServerDeps.Logger),并在 registerPlatformConsoleRoutes 中把 s.logger 透传给 RegisterConsoleOrganizationWorkspaceRoutes
  • RegisterConsoleOrganizationWorkspaceRouteshandleListConsoleWorkspaces 签名增加 logger *slog.Logger,使 workspace 列表 handler 通过 internalErrorWithCause 使用注入的 logger 记录错误与 request_id;仅在调用方未注入时回退 slog.Default()
  • 修正 isUndefinedRelationError 的 doc 注释,明确覆盖 console 查询读路径与 RemoveOrgUser 这类写路径,不再限定为 list handler。

两处改动均验证通过:logger 链路从 ServerDeps.LoggerinternalErrorWithCause 完整闭合,go build 通过。

Pullfrog  | View workflow run | Using anthropic/glm-5.2𝕏

@duckpr duckpr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DuckPR reviewer: opencode
Model: anthropic/glm-5.2

ℹ️ 合并干净,无新增严重问题 — 行内一处小建议。

Reviewed changes — 本轮将 PR 分支与 origin/main 合并(Yourbatis 迁移、UUID 迁移、slog 标准化等),PR 自身的 schema-drift 兜底逻辑已正确锚定到合并后的新代码结构上。

  • 两次 merge commit (7ec99cffede351) 把 origin/main 的 Yourbatis mapper 迁移、UUID 引用迁移和 slog 标准化(da3b4ed)合入 PR 分支。
  • ListConsoleAPIKeys / CountConsoleAPIKeysisUndefinedRelationError 守卫已重新锚定到 Yourbatis mapper 路径(mapper.List / mapper.CountUnarchived),旧 selectConsoleAPIKeysSQLX 调用点随之迁移。
  • internalErrorWithCause 的日志已切换为 ErrorContext(r.Context(), ...),与合并后的 main 分支 s.logger.ErrorContext 用法一致。
  • go build ./internal/platformapi/... ./internal/db/... ./internal/api/... 通过,merge 未遗留冲突。

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using anthropic/glm-5.2𝕏

if logger == nil {
logger = slog.Default()
}
logger.ErrorContext(r.Context(), message, "err", err, "request_id", httpapi.RequestID(r.Context()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ 合并后的 main 分支(da3b4ed slog 标准化)已统一用 "error" 作为错误属性名——internal/ 下所有其他 ErrorContext 调用都是 "error", err,这里是唯一使用 "err" 的地方。建议改为 "error", err 以保持一致,方便日志检索与过滤。

Technical details
# slog field name drift after merge

## Affected sites
- `internal/platformapi/support.go:153``logger.ErrorContext(r.Context(), message, "err", err, ...)`

## Required outcome
- 错误值统一用 `"error"` 属性名记录,与 `internal/api/server.go``internal/api/platform_mcp_vault_auth.go``internal/api/service_auth.go` 等全部 `s.logger.ErrorContext(... "error", err)` 一致。

## Suggested approach
将第 153 行的 `"err", err` 改为 `"error", err`,其余不变。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Console] workspaces API 在 schema 漂移时静默 500,连锁打挂前端工作空间上下文

1 participant