Skip to content

fix(bundler): preserve inner error codes instead of double-wrapping#702

Merged
mchmarny merged 3 commits into
mainfrom
fix/bundle-error-double-wrap
Apr 28, 2026
Merged

fix(bundler): preserve inner error codes instead of double-wrapping#702
mchmarny merged 3 commits into
mainfrom
fix/bundle-error-double-wrap

Conversation

@mchmarny

Copy link
Copy Markdown
Member

Summary

Stop bundler.Make() from clobbering inner structured error codes (e.g., INVALID_REQUEST, TIMEOUT) with ErrCodeInternal, so the API returns correct HTTP status codes and retryable values.

Motivation / Context

POST /v1/bundle returns HTTP 500 / INTERNAL / retryable: true for request-validation failures raised inside deployers. The inner error already carries ErrCodeInvalidRequest, but the outer wrap in runDeployer overwrites it with ErrCodeInternal. Clients that retry on 5xx hammer the server for errors that will never succeed.

Fixes: #679
Related: N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Build/CI/tooling

Component(s) Affected

  • CLI (cmd/aicr, pkg/cli)
  • API server (cmd/aicrd, pkg/api, pkg/server)
  • Recipe engine / data (pkg/recipe)
  • Bundlers (pkg/bundler, pkg/component/*)
  • Collectors / snapshotter (pkg/collector, pkg/snapshotter)
  • Validator (pkg/validator)
  • Core libraries (pkg/errors, pkg/k8s)
  • Docs/examples (docs/, examples/)
  • Other: ____________

Implementation Notes

At 4 call sites in pkg/bundler/bundler.go (runDeployer, extractComponentValues, copyDataFiles, collectComponentManifests), replaced unconditional errors.Wrap(ErrCodeInternal, ...) with a conditional pattern: if the inner error is already a *errors.StructuredError, return it as-is to preserve its code; otherwise wrap with ErrCodeInternal as before.

This follows the existing CLAUDE.md rule: "Don't double-wrap errors that already have proper codes."

Testing

make qualify   # all tests pass (pre-existing sandbox failures unrelated)
golangci-lint run -c .golangci.yaml ./pkg/bundler/...  # 0 issues

Added 3 new tests:

  • TestMake_PreservesInnerErrorCode — path-traversal component returns ErrCodeInvalidRequest
  • TestMake_PreservesTimeoutFromExtractValues — cancelled context returns ErrCodeTimeout
  • TestBundleEndpointPathTraversalReturns400 — HTTP integration: verifies 400 + INVALID_REQUEST + retryable: false

pkg/bundler coverage: 61.3% (no decrease)

Risk Assessment

  • Low — Isolated change, well-tested, easy to revert
  • Medium — Touches multiple components or has broader impact
  • High — Breaking change, affects critical paths, or complex rollout

Rollout notes: API clients that previously retried on these 500s will now see 400s. This is the correct behavior per the API contract — no migration needed.

Checklist

  • Tests pass locally (make test with -race)
  • Linter passes (make lint)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs if user-facing behavior changed
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S) — GPG signing info

…s INTERNAL

Stop runDeployer, extractComponentValues, copyDataFiles, and
collectComponentManifests from unconditionally wrapping structured errors
with ErrCodeInternal. When the inner error already carries a proper code
(e.g., ErrCodeInvalidRequest, ErrCodeTimeout), return it as-is so the
API layer maps it to the correct HTTP status.

Fixes #679
@mchmarny mchmarny requested a review from a team as a code owner April 28, 2026 14:30
@mchmarny mchmarny added the bug label Apr 28, 2026
@mchmarny mchmarny self-assigned this Apr 28, 2026
@mchmarny mchmarny enabled auto-merge (squash) April 28, 2026 14:31
@coderabbitai

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@github-actions

github-actions Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Coverage Report ✅

Metric Value
Coverage 75.2%
Threshold 70%
Status Pass
Coverage Badge
![Coverage](https://img.shields.io/badge/coverage-75.2%25-green)

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/NVIDIA/aicr/pkg/bundler 61.34% (+0.53%) 👍

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/NVIDIA/aicr/pkg/bundler/bundler.go 56.81% (+0.32%) 382 (+12) 217 (+8) 165 (+4) 👍

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

@mchmarny mchmarny disabled auto-merge April 28, 2026 14:53
@mchmarny mchmarny enabled auto-merge (squash) April 28, 2026 14:53
@mchmarny mchmarny merged commit cb6b98c into main Apr 28, 2026
30 checks passed
@mchmarny mchmarny deleted the fix/bundle-error-double-wrap branch April 28, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API /v1/bundle double-wraps INVALID_REQUEST as INTERNAL 500 (retryable: true)

2 participants