fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(errors): surface server code + message on coded 403s (AIT-151) - #15

Merged
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes
Jul 12, 2026
Merged

fix(errors): surface server code + message on coded 403s (AIT-151)#15
ord669 merged 2 commits into
mainfrom
ait-151-surface-server-403-codes

Conversation

@ord669

@ord669ord669 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem (AIT-151)

mapApiError's 403 branch collapsed almost every 403 into the blanket
This action requires workspace admin permission. string plus re-login
guidance. That hid the server's real reason for specific denials — e.g. a
self-only revoke (AGENT_KEY_REVOKE_SELF_ONLY) showed the wrong "ask your
admin" message. The --json error output also carried the multi-line human
CLI guidance instead of a machine-clean message.

Changes

  • Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
    INSTAGRAM_DISABLED special cases) now surface the server's own code and
    message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
    403 with no server code still falls back to the admin-guidance
    PermissionError.
  • Generic 4xx fallbacks preserve the server's code so scripts reading
    --json can branch on it instead of a flat API_ERROR.
  • The --json error envelope prefers a machine-clean single-line message when
    an error carries one (PermissionError.jsonMessage), instead of emitting its
    multi-line human guidance.

Verification

  • New tests: coded 403 (AGENT_KEY_REVOKE_SELF_ONLY) surfaces the server
    message + code and exits 3; PermissionError--json message is a clean
    single line; ForbiddenError carries server code/message.
  • Full suite green (933 tests), tsc --noEmit clean, build succeeds.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of HTTP 403 denials by preserving server-provided error codes and messages instead of substituting generic permission guidance.
    • Enhanced error output to produce cleaner, single-line summaries in JSON mode with accurate HTTP status and codes.
    • Updated login validation in the doctor workflow to treat these permission-style 403 failures consistently.
  • Tests
    • Added regression coverage for coded 403 scenarios and for JSON error payload structure.

The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
@coderabbitai

coderabbitaiBot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b9671c8-837f-420b-b7a7-7a5faaee6c41

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0b2f2 and 1c49318.

📒 Files selected for processing (1)
  • src/commands/doctor.ts

📝 Walkthrough

Walkthrough

Coded 403 responses now preserve server-provided codes and messages through API error mapping and JSON output. A new ForbiddenError represents non-admin-specific 403 denials, doctor classifies it as a credential failure, and regression tests cover the updated behavior.

Changes

Coded 403 Error Handling

Layer / File(s)Summary
Error taxonomy and JSON output
src/output/error.ts
Adds ForbiddenError, supports optional server codes in ApiError, and emits clean JSON messages when available.
API 403 mapping
src/api/client.ts
Maps coded 403 responses to ForbiddenError and preserves server codes in generic API errors.
Doctor credential classification
src/commands/doctor.ts
Classifies ForbiddenError with authentication and permission failures during credential validation.
Regression coverage
src/__tests__/api-403-handler.spec.ts, src/auth/__tests__/bootstrap.test.ts, src/output/__tests__/error.test.ts
Verifies coded 403 messages, codes, exit codes, and JSON serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
participant apiClient
participant mapApiError
participant ForbiddenError
participant doctor
apiClient->>mapApiError: Process coded 403 response
mapApiError->>ForbiddenError: Create with server message and code
ForbiddenError-->>apiClient: Return exitCode 3 error
doctor->>apiClient: Validate credentials
apiClient-->>doctor: Return ForbiddenError
doctor->>doctor: Classify credential failure
Loading

Possibly related PRs

  • hookmyapp/cli#4: Also changes mapApiError mappings for server-provided error codes and statuses.
  • hookmyapp/cli#12: Also updates mapApiError to map a server error code to a specific recovery behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly summarizes the main change: surfacing server code and message for coded 403 responses.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ait-151-surface-server-403-codes

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

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:9e0b2f2238

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/api/client.ts
@ord669
ord669 merged commit 68e8f38 into mainJul 12, 2026
3 checks passed
@ord669
ord669 deleted the ait-151-surface-server-403-codes branch July 12, 2026 17:05
ord669 added a commit that referenced this pull request Aug 12, 2026
* fix(errors): surface server code + message on coded 403s (AIT-151)
The 403 branch in mapApiError collapsed almost every 403 into the blanket
"This action requires workspace admin permission." string plus re-login
guidance, hiding the server's real reason for denials like
AGENT_KEY_REVOKE_SELF_ONLY.
- Coded 403s (any code beyond the existing SESSION_WINDOW_CLOSED /
INSTAGRAM_DISABLED special cases) now surface the server's own code and
message via a new ForbiddenError (exit 3, the 403 permission tier). A bare
403 with no server code still falls back to the admin-guidance
PermissionError.
- Generic 4xx fallbacks now preserve the server's code so scripts reading
--json can branch on it instead of a flat API_ERROR.
- The --json error envelope now prefers a machine-clean single-line message
when an error carries one (PermissionError), instead of emitting its
multi-line human CLI guidance.
* fix(doctor): treat coded 403s (ForbiddenError) as rejected credentials
Sign up for freeto 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.

1 participant

@ord669