Skip to content

fix(apps): detect the no-database failure by code or message - #2217

Merged
chenxingyang1019 merged 3 commits into
mainfrom
fix/apps-no-database-error-match
Aug 7, 2026
Merged

fix(apps): detect the no-database failure by code or message#2217
chenxingyang1019 merged 3 commits into
mainfrom
fix/apps-no-database-error-match

Conversation

@chenxingyang1019

@chenxingyang1019 chenxingyang1019 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Problem

withAppsHint special-cases one failure — a db command run against an app that has no database yet — by rewriting the server's message into a user-facing explanation and attaching a cloud-development recovery hint. That special case was keyed on a single business code, 500002759.

The server has since renumbered this case to 400002465, moving it into the 4xx band with the rest of its client-class errors. The branch no longer fires, so:

  • the raw server message reaches the user. It is internal vocabulary about workspace ↔ app-id mapping — exactly what the rewrite exists to hide.
  • the recovery steps are replaced by a generic "verify --app-id" hint that points at +db-env-create, which is not a valid next step for an app that has no database at all.

Nothing catches a renumber. There is no compile error, and the unit tests compare against the same constant they set, so they pass either way.

Separately, none of the db-domain codes were registered in the Spark code table, so BuildAPIError fell through to the CategoryAPI + SubtypeUnknown catch-all: the envelope carried no usable classification and an agent could only branch on the raw number.

Change

Detect the no-database failure on code OR message. Codes 400002465 (current) and 500002759 (legacy, kept so older servers still match), plus narrow lowercase markers of the server's internal wording. The two channels have opposite failure modes — a code is precise but gets renumbered, a message survives renumbering but breaks on rewording or localization. Requiring either to match means one channel changing degrades nothing, and only a simultaneous change of both regresses.

Markers stay deliberately narrow: "no db branch" must not also swallow env-pull's "invalid db branch" case, which needs its own hint. A comment records that widening them requires a test proving the neighbours still pass through.

Classify the db-domain codes. No-database registers as Validation / FailedPrecondition — the app resolves fine and the request is well-formed, but a prerequisite the caller must create first is missing, so retrying unchanged can never succeed. This moves its exit code from 1 to 2 ("fix the state" rather than "the call failed"). Table-not-found registers as API / NotFound, an ordinary missing-resource lookup with no exit-code change.

The two layers stay separate on purpose: the code table sets classification, the shortcut layer owns the message rewrite and the recovery hint, and its message channel is what still fires if the codes are renumbered again.

Nothing outside these paths changes. For the no-database failure, the cause chain is untouched and the helper still mutates in place rather than returning a replacement error.

Tests

TestWithAppsHint gains cases for the legacy code, an unknown code matched by message (case-insensitive, substring), and a wrapped cause asserted to survive the rewrite. Negative controls prove "invalid db branch: dev", "数据表格不存在" and "permission denied" keep the caller's hint. Every case asserts Category, Subtype and Code are unchanged and that the same error value comes back. withAppsHint and isAppNoDatabaseError are both at 100% statement coverage.

On the classifier side, one test pins the exit code the no-database codes route to, so a future reclassification has to be deliberate; another pins that SubtypeNotFound leaves Hint empty, since the shortcut layer fills its command-scoped hint only when the classifier left one empty.

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of database initialization failures across current and legacy error formats.
    • Added clearer recovery guidance when the database is unavailable.
    • Preserved underlying error details and avoided misclassifying unrelated database errors.
    • Improved handling of case variations, embedded server messages, and missing error values.
    • Corrected error classification and shell exit codes for database initialization failures.

@github-actions github-actions Bot added the size/M Single-domain feat or fix with limited business impact label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The app error flow detects database initialization failures through current and legacy codes or matching server messages. withAppsHint applies the recovery message and hint. Spark metadata classifies both codes as validation failures with failed-precondition subtypes.

Changes

Database error detection and recovery

Layer / File(s) Summary
Database error detector and recovery hint
shortcuts/apps/common.go
The detector recognizes current and legacy database codes and lowercase server-message markers. withAppsHint uses the detector.
Spark error classification
internal/errclass/codemeta_spark.go
Both no-database Spark codes map to CategoryValidation and SubtypeFailedPrecondition.
Recovery and classification validation
shortcuts/apps/common_test.go, internal/errclass/codemeta_spark_test.go
Tests verify message-based and legacy-code detection, preserved causes and classification, recovery hints, unrelated errors, nil input, and exit code 2.

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

Possibly related PRs

  • larksuite/cli#2162: Introduced the withAppsHint no-database error handling that this change extends.

Suggested reviewers: liangshuo-1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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 Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: detecting the no-database failure by code or message.
Description check ✅ Passed The description is detailed and on-topic, covering the problem, changes, classification, recovery behavior, and tests, although it does not use the template headings.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/apps-no-database-error-match

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.

@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: 2

🤖 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 `@shortcuts/apps/common_test.go`:
- Around line 98-135: Extend the affected tests around the legacy, unknown-code,
and unrelated-failure cases to assert the resulting error’s expected Category
and Subtype, retaining each input error for comparison. Add a wrapped-cause
scenario and verify the error returned through errs.ProblemOf preserves that
cause chain, without asserting a nonexistent Param field.

In `@tests/cli_e2e/apps/apps_env_pull_live_test.go`:
- Around line 31-33: Remove the LARKSUITE_CLI_CONFIG_DIR requirement from the
setup of this live workflow test. Use the established live-token gate for
skipping unavailable credentials, while retaining
LARK_CLI_E2E_APPS_ENV_PULL_APP_ID as the fixture gate.
🪄 Autofix

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: 3863f1f6-3e80-4aa0-8922-c48d80da1c81

📥 Commits

Reviewing files that changed from the base of the PR and between 164d3cc and d4162da.

📒 Files selected for processing (4)
  • shortcuts/apps/common.go
  • shortcuts/apps/common_test.go
  • tests/cli_e2e/apps/apps_env_pull_live_test.go
  • tests/cli_e2e/apps/coverage.md

Comment thread shortcuts/apps/common_test.go
Comment thread tests/cli_e2e/apps/apps_env_pull_live_test.go Outdated
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@329b571ec0ee9ae08b1c7cb8270370c16f951a1e

🧩 Skill update

npx skills add larksuite/cli#fix/apps-no-database-error-match -y -g

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.34%. Comparing base (f7d0326) to head (329b571).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2217      +/-   ##
==========================================
+ Coverage   76.22%   76.34%   +0.12%     
==========================================
  Files         987      991       +4     
  Lines      104280   106029    +1749     
==========================================
+ Hits        79486    80952    +1466     
- Misses      18751    18942     +191     
- Partials     6043     6135      +92     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@chenxingyang1019
chenxingyang1019 force-pushed the fix/apps-no-database-error-match branch from d4162da to 4d1a04a Compare August 6, 2026 11:52
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@chenxingyang1019 chenxingyang1019 changed the title fix(apps): detect the no-database failure by code or message, and add +env-pull live E2E fix(apps): detect the no-database failure by code or message Aug 6, 2026
@chenxingyang1019

chenxingyang1019 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the two review threads:

common_test.go — assert the full typed-error contract. Valid, fixed. Each of the new cases now asserts Category, Subtype and Code survive the rewrite and that the helper returns the same error value; inputs use a concrete subtype instead of Unknown so a clobbered classification is observable. Added a wrapped-cause case asserting errors.Is still finds the cause through the rewrite. Did not assert Param — as noted, it does not apply to these API errors.

apps_env_pull_live_test.go — do not require an isolated config dir. No longer applicable: that file was dropped, so this PR is scoped to the no-database detection fix alone.

Also closed the coverage gap the report flagged: withAppsHint and isAppNoDatabaseError are both at 100% now.

The recovery flow for "db command against an app that has no database"
keyed on one business code (500002759). The server has since renumbered
that case to 400002465, which silently disabled the flow: users now see
the raw internal message about workspace / app-id mapping and lose the
cloud-development recovery steps entirely.

Nothing catches the regression. There is no compile error, the unit tests
compare against the same constant they set, and the dry-run E2E does not
exercise a real response — the failure only shows up against a server that
has already renumbered.

Detect on code OR message instead. Both known codes are kept, plus narrow
lowercase markers of the server's internal wording. The two channels have
opposite failure modes: a code is precise but gets renumbered, a message
survives renumbering but breaks on rewording or localization. Requiring
either to match means one channel changing degrades nothing, and only a
simultaneous change of both regresses.

Markers stay deliberately narrow. "no db branch" in particular must not
also swallow env-pull's "invalid db branch" case, which needs its own
hint; a comment records that widening them requires a test proving the
neighbours still pass through.

Classification and the cause chain are untouched: the helper still mutates
the problem in place and returns the same error value.
Review feedback: the new subtests checked only Message and Hint, so a
change that reclassified the failure — or replaced the error value and
dropped the cause chain — would still have passed.

Each case now asserts Category, Subtype and Code are untouched by the
rewrite, and that the helper returns the same error value. Inputs use a
concrete subtype rather than Unknown, so a clobbered classification is
actually observable. One new case wraps a cause and asserts errors.Is
still finds it through the rewrite.

Also covers the predicate's defensive nil guard, which withAppsHint cannot
reach on its own (ProblemOf returns ok=false for untyped errors), closing
the two uncovered lines the coverage report flagged. Both withAppsHint and
isAppNoDatabaseError are now at 100%.
@chenxingyang1019
chenxingyang1019 force-pushed the fix/apps-no-database-error-match branch from 2f82630 to b877e53 Compare August 7, 2026 02:29
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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/errclass/codemeta_spark_test.go`:
- Around line 34-37: Add parameter assertions to the shared validation-case test
covering codes 400002465 and 500002759: use errors.As to extract
*errs.ValidationError from the returned error and assert its Param is empty,
while preserving the existing category, subtype, code, log ID, and retryability
checks.
🪄 Autofix

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: bfae2f15-b270-48dc-b2c7-d452413a452c

📥 Commits

Reviewing files that changed from the base of the PR and between b877e53 and 79073d5.

📒 Files selected for processing (2)
  • internal/errclass/codemeta_spark.go
  • internal/errclass/codemeta_spark_test.go

Comment thread internal/errclass/codemeta_spark_test.go Outdated
Three codes reaching the Apps db commands were absent from the Spark
table, so BuildAPIError fell through to the CategoryAPI + SubtypeUnknown
catch-all and the envelope carried no usable classification.

"App has no database yet" registers as Validation / FailedPrecondition:
the app resolves fine and the request is well-formed, but a prerequisite
the caller must create first is missing, so retrying unchanged can never
succeed. This moves its exit code from 1 to 2 — "fix the state" rather
than "the call failed" — and a test pins that so a future
reclassification has to be deliberate. Two codes cover it because the
server renumbered the case into the 4xx band; the legacy one stays for
older servers.

"Table does not exist" registers as API / NotFound, an ordinary
missing-resource lookup with no exit-code change. SubtypeNotFound has no
APIHint default, which matters here: the Apps layer fills its
command-scoped hint only when the classifier left Hint empty, so a
context-free default would displace the more actionable one. A test
guards that too.
@chenxingyang1019
chenxingyang1019 force-pushed the fix/apps-no-database-error-match branch from 0de0c88 to 329b571 Compare August 7, 2026 04:02
@chenxingyang1019
chenxingyang1019 merged commit 6402080 into main Aug 7, 2026
58 of 60 checks passed
@chenxingyang1019
chenxingyang1019 deleted the fix/apps-no-database-error-match branch August 7, 2026 07:13
@liangshuo-1 liangshuo-1 mentioned this pull request Aug 7, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants