Skip to content

fix(errors): extract API error body from GenericOpenAPIError#52

Merged
platinummonkey merged 2 commits into
mainfrom
fix/extract-api-error-body
Feb 12, 2026
Merged

fix(errors): extract API error body from GenericOpenAPIError#52
platinummonkey merged 2 commits into
mainfrom
fix/extract-api-error-body

Conversation

@maruina
Copy link
Copy Markdown
Member

@maruina maruina commented Feb 12, 2026

Problem

datadog-api-client-go consumes http.Response.Body during deserialization and stores the raw bytes in datadog.GenericOpenAPIError. formatAPIError() re-read http.Response.Body, which was always empty by that point. Users saw only:

Error: failed to query metrics: 400 Bad Request (status: 400)

No indication of what went wrong.

Fix

Extract the response body from GenericOpenAPIError.Body() instead of re-reading the drained http.Response.Body. API errors now surface the actual server response:

Error: failed to query metrics: 400 Bad Request
Status: 400
API Response: {"errors":["Error parsing query: unable to parse avg:this.metric.does.not.exist.at:
Rule 'scope_expr' didn't match at '' (line 1, column 34)."]}

Changes

  • Add extractAPIErrorBody() — unwraps GenericOpenAPIError and returns the stored body (cmd/root.go:264)
  • Call extractAPIErrorBody() from formatAPIError() to include the body in all API error paths (cmd/root.go:291)
  • Apply the same extraction in cmd/logs_simple.go and cmd/metrics.go for direct error handling

Testing

  • Unit tests for extractAPIErrorBody: body present, empty body, nil body, non-API error, nil error (cmd/root_test.go:323)
  • Integration test: formatAPIError includes the response body in output (cmd/root_test.go:375)
  • Manual: pup metrics query --query="avg:invalid.metric" --from="1h" shows the full API parse error

🤖 Generated with Claude Code

The datadog-api-client-go library consumes http.Response.Body during
deserialization and stores the raw bytes in GenericOpenAPIError.ErrorBody.
The error handling in metrics and logs commands was trying to re-read
http.Response.Body via io.ReadAll, which always returned empty data
since the body was already consumed. This silently discarded the actual
API error details, making 400/4xx errors impossible to diagnose.

- Add extractAPIErrorBody() helper that uses errors.As to extract the
  response body from GenericOpenAPIError
- Replace all 10 broken io.ReadAll(r.Body) calls in cmd/metrics.go and
  cmd/logs_simple.go with the new helper
- Enhance formatAPIError() to include the API response body when
  available
- Add tests for extractAPIErrorBody and formatAPIError body inclusion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 12, 2026

📊 Test Coverage Report

Overall Coverage: 81.7% Coverage

Threshold: 80% ✅

Coverage by Package
## Coverage by Package

- github.com/DataDog/pup/pkg/auth/callback/server.go:40: 81.2%
- github.com/DataDog/pup/pkg/auth/dcr/client.go:28: 100.0%
- github.com/DataDog/pup/pkg/auth/dcr/types.go:24: 100.0%
- github.com/DataDog/pup/pkg/auth/oauth/client.go:22: 100.0%
- github.com/DataDog/pup/pkg/auth/oauth/pkce.go:24: 85.7%
- github.com/DataDog/pup/pkg/auth/storage/factory.go:53: 94.7%
- github.com/DataDog/pup/pkg/auth/storage/keychain.go:44: 42.9%
- github.com/DataDog/pup/pkg/auth/storage/storage.go:58: 71.4%
- github.com/DataDog/pup/pkg/auth/types/types.go:23: 100.0%
- github.com/DataDog/pup/pkg/client/client.go:32: 94.4%
- github.com/DataDog/pup/pkg/config/alias.go:26: 100.0%
- github.com/DataDog/pup/pkg/config/config.go:22: 100.0%
- github.com/DataDog/pup/pkg/formatter/formatter.go:31: 100.0%
- github.com/DataDog/pup/pkg/useragent/useragent.go:32: 100.0%
- github.com/DataDog/pup/pkg/util/time.go:28: 96.0%

## Summary

total:								(statements)		81.7%

📈 Coverage Status: ✅ PASSED - Coverage meets minimum threshold

Updated for commit cab8890

@maruina maruina marked this pull request as ready for review February 12, 2026 09:55
@maruina maruina requested a review from a team as a code owner February 12, 2026 09:56
- Add wrapped GenericOpenAPIError test case to verify errors.As unwrapping
- Expand formatAPIError doc comment to describe body extraction behavior
- Document why inline error handlers bypass formatAPIError
- Fix pre-existing string(rune(tt.code)) producing Unicode garbage in subtest names

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@platinummonkey platinummonkey merged commit 634811b into main Feb 12, 2026
4 checks passed
@platinummonkey platinummonkey deleted the fix/extract-api-error-body branch February 12, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants