Skip to content

fix: add actionable hints and doc links to Atmos Pro API errors - #2264

Merged
Andriy Knysh (aknysh) merged 4 commits into
mainfrom
osterman/pro-error-hints
Mar 28, 2026
Merged

Andriy Knysh (aknysh) merged 4 commits into
mainfrom
osterman/pro-error-hints

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Mar 27, 2026 •

Copy link
Copy Markdown
Member

what

  • Wrap all Atmos Pro API errors in the Error Builder pattern with status-specific hints and documentation links
  • Add ui.Success/ui.Error messages when --upload completes or fails (previously silent on success, swallowed on failure)
  • Consolidate fragmented hints into self-contained statements (each hint gets its own lightbulb icon)
  • Remove duplicate quickstart links from 404 hints
  • Replace fmt.Errorf error wrapping with errors.Join + buildProAPIError across all Pro API paths (uploads, lock/unlock, OIDC exchange)

why

  • Users seeing a 403 from Atmos Pro had no guidance on what to do — the error message was opaque (e.g. API request failed with status 403). The most common cause is per-repo permissions not being configured.
  • Each HTTP status now links to the most relevant Atmos Pro doc page:
  • Successful uploads were completely silent — users had no confirmation the upload worked
  • Upload failures were silently swallowed (log.Warn only) — now they surface as proper errors with hints

references

Summary by CodeRabbit

  • Bug Fixes

    • API errors now include richer context (HTTP status, operation, trace IDs) and status-specific troubleshooting hints; non-JSON responses include a troubleshooting link. Token exchange and lock/unlock failures surface improved, consistent error information.
  • New Features

    • User-facing success and error notifications when uploading affected stacks.
  • Tests

    • Added tests validating status-specific hints, non-JSON error handling, and trace ID presence.

Wrap all Pro API errors in the error builder pattern so users get
status-specific guidance instead of opaque HTTP status codes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the size/m Medium size PR label Mar 27, 2026
@github-actions

github-actions Bot commented Mar 27, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 1f68aef.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@osterman Erik Osterman (Cloud Posse) (osterman) added the patch A minor, backward compatible change label Mar 27, 2026
@coderabbitai

coderabbitai Bot commented Mar 27, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 708a4e70-2130-4653-9fa0-1f1ab3485a47

📥 Commits

Reviewing files that changed from the base of the PR and between 7fad884 and 1f68aef.

📒 Files selected for processing (2)
  • pkg/pro/api_client.go
  • pkg/pro/api_client_test.go

📝 Walkthrough

Walkthrough

Reworked Atmos Pro API client error handling to replace string-wrapped errors with structured, enriched errors using errors.Join and a new buildProAPIError. Tests added for status-specific hints and non-JSON responses. Also surface upload failures to the UI in internal/exec/describe_affected.go.

Changes

Cohort / File(s) Summary
Core API Error Handling
pkg/pro/api_client.go
Replaced fmt.Errorf-style wrapping with errors.Join; added buildProAPIError(operation, statusCode, apiResponse) to normalize status codes, attach causes, operation/status metadata, optional trace_id, and status-specific troubleshooting hints; updated handleAPIResponse, doStackLockAction, and exchangeOIDCTokenForAtmosToken to use the new error construction.
Error Handling Tests
pkg/pro/api_client_test.go
Added table-driven and explicit tests verifying buildProAPIError hint selection across HTTP statuses (401/403/404/5xx/400), trace_id inclusion, and that handleAPIResponse enriches non-JSON error responses with the unmarshalling error and troubleshooting hints; also assert success for non-JSON 2xx cases and status-inferred successes.
CLI UX for Upload Failures
internal/exec/describe_affected.go
Replaced silent warning on UploadAffectedStacks failure with ui.Error(...) and returned the error; added ui.Success(...) on successful upload to surface result to users.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • milldr
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding actionable hints and documentation links to Atmos Pro API errors, which aligns with the core objective of improving error messaging across multiple API paths.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 osterman/pro-error-hints

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/pro/api_client_test.go`:
- Around line 567-640: Add a regression row to
TestBuildProAPIError_HintsPerStatusCode that simulates the real bug: call
buildProAPIError with a non-zero statusCode (e.g., http.StatusUnauthorized or
http.StatusForbidden) but pass an apiResponse whose Status field is zero
(omitted), then assert the produced error still contains the expected
status-specific hints; locate the test table in pkg/pro/api_client_test.go and
the buildProAPIError helper to add the case (e.g., name "401 with missing
response status" with statusCode http.StatusUnauthorized and apiResponse.Status
left at 0) and include the same expectedHints as the normal 401/403/404/500
rows.

In `@pkg/pro/api_client.go`:
- Around line 302-315: The LockStackResponse/UnlockStackResponse handling
currently only calls buildProAPIError after a successful JSON decode and thus
returns raw decode errors for non-JSON (HTML/plain) responses; update the switch
in the function handling params.Out to mirror handleAPIResponse: after calling
logProAPIResponse(params.Op, responseData.AtmosApiResponse), if JSON decoding
failed or response body wasn't JSON then check resp.StatusCode (e.g.,
401/403/404/5xx) and return a user-facing error that includes the
troubleshooting/guidance text (same guidance used by handleAPIResponse) combined
with detailed debug info (wrap in params.WrapErr and include buildProAPIError
when appropriate) so non-JSON failures on LockStack/UnlockStack produce the same
helpful messages as other API paths. Ensure you reference params.Op,
params.WrapErr, resp.StatusCode, logProAPIResponse, buildProAPIError,
dtos.LockStackResponse and dtos.UnlockStackResponse when implementing.
- Around line 414-449: buildProAPIError currently lets the human-facing/fallback
message come from apiResponse.Status which can be 0 and hide the transport
status; update buildProAPIError so the transport statusCode is the canonical
source for status: if apiResponse.Status == 0 set apiResponse.Status =
statusCode (or pass statusCode into logAndReturnProAPIError) before calling
logAndReturnProAPIError, and keep using the statusCode variable for hint
selection (function buildProAPIError and helper logAndReturnProAPIError are the
relevant symbols to change).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fabec5df-cfca-4fb9-961c-05f585a76007

📥 Commits

Reviewing files that changed from the base of the PR and between eb963b9 and 99f6bc8.

📒 Files selected for processing (2)
  • pkg/pro/api_client.go
  • pkg/pro/api_client_test.go

Comment thread pkg/pro/api_client_test.go
Comment thread pkg/pro/api_client.go Outdated
Comment thread pkg/pro/api_client.go
- Show ui.Success/ui.Error messages when --upload completes or fails
- Return upload errors instead of silently swallowing them
- Merge 5xx hint fragments into one self-contained hint with doc link
- Remove duplicate quickstart link from 404 hints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Mar 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 67.79661% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.27%. Comparing base (eb963b9) to head (1f68aef).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/pro/api_client.go 71.42% 13 Missing and 3 partials ⚠️
internal/exec/describe_affected.go 0.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2264      +/-   ##
==========================================
+ Coverage   77.23%   77.27%   +0.04%     
==========================================
  Files        1020     1020              
  Lines       96481    96530      +49     
==========================================
+ Hits        74515    74597      +82     
+ Misses      17766    17734      -32     
+ Partials     4200     4199       -1     
Flag Coverage Δ
unittests 77.27% <67.79%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/exec/describe_affected.go 56.43% <0.00%> (-0.48%) ⬇️
pkg/pro/api_client.go 88.65% <71.42%> (-2.67%) ⬇️

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…hints

Address CodeRabbit review findings where error hints could be bypassed:
- Normalize statusCode in buildProAPIError so hints work even when JSON
  body omits the status field (status=0)
- Pass resp.StatusCode from doStackLockAction and exchangeOIDCTokenForAtmosToken
  instead of the response body status
- Add enriched error handling for non-JSON responses in lock/unlock and
  OIDC token exchange paths (matching handleAPIResponse pattern)
- Add regression tests for status=0 in response body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 the current code and only fix it if needed.

Inline comments:
In `@pkg/pro/api_client.go`:
- Around line 423-468: buildProAPIError currently unconditionally adds a 5xx
hint that says "will be retried automatically", which is inaccurate for
operations that are not wrapped by doWithRetry (e.g., LockStack/UnlockStack via
doStackLockAction and ExchangeOIDCToken) while others (UploadAffectedStacks,
UploadInstances, UploadInstanceStatus) do retry; fix by making the hint
conditional: add a boolean parameter (e.g., isRetried) to buildProAPIError or
derive retryability via an explicit operation-name whitelist, update all callers
(including doStackLockAction, ExchangeOIDCToken, UploadAffectedStacks,
UploadInstances, UploadInstanceStatus) to pass the correct value, and only
append the "will be retried automatically" 5xx hint when isRetried is true
(otherwise use a neutral server-error hint).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4753229f-b4a0-48d8-888d-004186a462c5

📥 Commits

Reviewing files that changed from the base of the PR and between 99f6bc8 and 7fad884.

📒 Files selected for processing (3)
  • internal/exec/describe_affected.go
  • pkg/pro/api_client.go
  • pkg/pro/api_client_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/pro/api_client_test.go

Comment thread pkg/pro/api_client.go
- Remove "will be retried automatically" from 5xx error hint — not all
  callers use doWithRetry (lock/unlock, OIDC exchange don't retry)
- Add TestHandleAPIResponse_NonJSONErrorResponse: covers non-JSON body
  with error status returning enriched error with troubleshooting link
- Add TestHandleAPIResponse_NonJSONSuccessResponse: covers non-JSON body
  with success status returning nil
- Add TestHandleAPIResponse_SuccessHTTPStatusRange: covers 201 Created
  trusting HTTP status over missing Success field
- Add TestBuildProAPIError_WithTraceID: covers trace_id context in hints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aknysh
Andriy Knysh (aknysh) merged commit 66845bf into main Mar 28, 2026
56 checks passed
@aknysh
Andriy Knysh (aknysh) deleted the osterman/pro-error-hints branch March 28, 2026 15:05
@github-actions

Copy link
Copy Markdown

These changes were released in v1.214.0-rc.1.

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

Labels

patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants