Classify disabled-API 403s as misconfigured instead of expired - #1402
Merged
Conversation
A SERVICE_DISABLED / accessNotConfigured 403 means the API is disabled in the OAuth client's project; the credential is fine. Probes now classify it as a new 'misconfigured' status: amber 'API disabled' badge, the provider's own remediation text (console link clickable) on the row, and no reconnect prompt.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | 70961c9 | Commit Preview URL Branch Preview URL |
Aug 28 2026, 09:30 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | 70961c9 | Aug 28 2026, 09:32 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
The remediation text is the payload - the enable-API console link was clipped by the one-line truncate. The scenario now asserts the text wraps un-clipped and the link sits inside the visible box.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A Google 403 with reason accessNotConfigured / SERVICE_DISABLED means the API is disabled in the OAuth client's project; the credential itself still works. Health checks previously folded every 401/403 into the expired status, so these connections showed an Expired badge and a reconnect prompt that could not fix the problem.
Probes now classify that case as a new misconfigured status. The row shows an amber "API disabled" badge with the provider's own remediation message (console link clickable), and Check now explains the disabled API instead of prescribing a reconnect. Unrecognized 403s still classify as expired.
Invariant set: every consumer of the HealthStatus union
HealthStatusgoes from four literals to five. There is no exhaustiveswitchon it anywhere in the tree, so the compiler does not catch a missed consumer on
its own. The full set was enumerated before the change; each site below is
either compile-enforced or was reviewed and given a deliberate answer for the
new state.
Compile-enforced (a missing entry fails the build) — all updated:
packages/react/src/lib/health-display.ts—HEALTH_STATUS_LABEL,HEALTH_TEXT_CLASS,HEALTH_INDICATOR_COLOR,HEALTH_BADGE_VARIANT, and theHEALTH_SEVERITYordering map. These fiveRecord<HealthStatus, …>maps arethe only exhaustiveness enforcement that exists, so they are the safety net a
sixth literal would trip.
misconfiguredsorts abovedegradedand belowexpired, and shares degraded's amber rather than expired's destructive red.Reviewed, no change required (single-literal comparisons that already fall to a
correct default):
packages/react/src/lib/use-connection-health.ts— revalidation keys off=== "healthy"; anything else revalidates, which is right for the new state.packages/react/src/lib/admin-users-display.ts—connectionHealthStatusisa passthrough with an
?? "unknown"default.packages/react/src/pages/admin-users.tsx— renders only through the Recordmaps above.
packages/react/src/components/integration-health-summary.tsx— aggregatesvia
worstHealthStatusand reads the Record maps.packages/plugins/openapi/src/sdk/backing.ts— the=== "healthy"gates onidentity/sample extraction.
Reviewed and updated:
packages/react/src/components/accounts-section.tsx—misconfiguredisdeliberately kept OUT of
needsHealthAttention(expired/degraded): it gets itsown amber "API disabled" badge and its own link-rendered detail, because the
remediation is a console visit, not a reconnect. The
handleChecktoast chaingained an explicit
misconfiguredarm ahead of its catch-all.packages/react/src/components/add-account-modal.tsx— the tone ternary namesmisconfiguredso it does not fall through to the destructive colour.packages/core/api/src/admin/api.ts— theAdminConnectionHealth.statusdoccomment listed only the four old states; it now names all five.
packages/plugins/openapi/src/sdk/backing.ts— the one call site switched fromclassifyHttpStatusto the body-awareclassifyProbeResponse. This is whatlets
misconfiguredbe produced at all.Deliberately NOT emitting the new status:
packages/plugins/graphql/src/sdk/plugin.ts(healthFromIntrospectionError)and
packages/plugins/mcp/src/sdk/plugin.ts(mcpLivenessFailureStatus) keepfolding 401/403 into
expired. Neither carries the structured error envelopethe carve-out reads, and the reason markers are Google-shaped, so a GraphQL or
MCP endpoint cannot produce this verdict. Matching on message text instead
would risk a false
misconfigured, which would hide a genuinely deadcredential — the failure this classification is explicitly designed to avoid.
mcpLivenessFailureStatusalready narrows its own return to"expired" | "degraded", so it is unaffected by the wider union.Distinct from dead-grant classification: a disabled API is a health-probe
verdict about a working credential; a dead grant is a refresh-time verdict about
a credential that can no longer be renewed. That classification lives in
oauth-helpers.ts/executor.tsand referencesHealthStatusnowhere, so thetwo do not collide.