Skip to content

fix(cli): reject oversized deployment archives - #370

Open
AarjavPatni wants to merge 4 commits into
mainfrom
apatni/eng-1907-handle-oversized-archive-uploads-in-bl-deploy
Open

fix(cli): reject oversized deployment archives#370
AarjavPatni wants to merge 4 commits into
mainfrom
apatni/eng-1907-handle-oversized-archive-uploads-in-bl-deploy

Conversation

@AarjavPatni

@AarjavPatni AarjavPatni commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary

bl deploy and bl push now reject archives larger than the 5 GiB single-PUT limit before they send remote apply or image-build requests.

Volume templates get a metadata-only size check before the CLI creates a temporary TAR. Source-code deployments direct users to .blaxelignore; volume-template deployments explain that .blaxelignore is not used and direct users to reduce the template directory.

Live dev verification

  • A small volume template deployed successfully in 1.26 seconds.
  • An 8 GiB volume template originally failed after TAR creation in 3.19 seconds.
  • With the pre-TAR check, the same input failed in 0.36 seconds before a temporary TAR was created.
  • A subsequent GET returned 404, which confirmed that the oversized resource was not created.
Compressing volume template files...
Deploy failed
Reason: error generating blaxel deployment: failed to tar file: archive size exceeds the 5 GB upload limit; reduce the files in the volume template directory (.blaxelignore is not used for volume templates)

Verification

  • make lint
  • go build ./...
  • make test
  • Real dev deployments with small and 8 GiB volume templates
  • Agent code review: no findings after fixes

Review Guide

Why

Blaxel rejects deployment archives larger than 5 GiB. The CLI now detects this local validation failure before it sends unnecessary API or upload requests.

Behavior

  • Reject archives larger than 5 GiB. Allow an archive of exactly 5 GiB.
  • Check bl deploy and bl push archives before remote requests.
  • Check volume-template file metadata before TAR creation to avoid writing an oversized temporary archive.
  • Keep a final size guard at the upload boundary.
  • Do not retry an oversized upload.
  • Recommend .blaxelignore for source archives. Explain that volume templates do not use it.
  • Mark the failure as CLIErrorValidation. This prevents expected Sentry noise while errors.Is(err, errArchiveTooLarge) remains true.

Execution Flow

flowchart LR
    A[bl deploy or bl push] --> B[Create archive]
    A --> C[Volume-template metadata scan]
    C -->|Over 5 GiB| X[Expected validation error]
    C -->|Within limit| B
    B --> D[Validate final archive size]
    D -->|Over 5 GiB| X
    D -->|Within limit| E[Apply or request upload URL]
    E --> F[Upload guard]
    F -->|Over 5 GiB| X
    F -->|Other upload error| G[Retry with refreshed URL]
    F -->|Success| H[Complete]
Loading

Invariants And Failure Paths

  • size <= 5 GiB is valid; size > 5 GiB is invalid.
  • Volume-template metadata accounting excludes blaxel.toml, as TAR creation does.
  • Oversized volume templates fail before the temporary TAR file is created.
  • Final archive validation runs before deploy or image-build requests.
  • The upload guard handles archive changes and other missed preflight paths.
  • UploadWithRetry returns errArchiveTooLarge immediately and does not refresh the URL.
  • core.MarkExpectedError preserves the wrapped sentinel and classifies the failure as expected validation.

Reading Order

  1. cli/deploy_test.go - Review boundary, guidance, pre-TAR, sentinel, and no-retry cases.
  2. cli/deploy.go - Review the shared limit, error classification, preflight checks, TAR scan, and upload guard.
  3. cli/push.go - Confirm that push validates the archive before the image-build request.
  4. cli/core/sentry.go - Confirm expected-error unwrapping and Sentry classification behavior.

Note

Medium Risk
Changes sit on the main deploy/push and upload paths, but behavior is additive validation with clear errors rather than altered platform contracts.

Overview
bl deploy and bl push now stop before remote apply or POST /images when the packaged archive exceeds the 5 GiB single-PUT limit.

Shared helpers ValidateArchiveSize, archiveSizeError, and errArchiveTooLarge centralize the cap. Oversized source archives tell users to trim via .blaxelignore; volume templates explain that ignore rules do not apply and the template directory must be smaller.

Volume templates sum regular-file metadata in Tar() before creating a temp TAR (skipping blaxel.toml), so huge trees fail fast without a multi‑GB local archive. Interactive deploy runs compression in runInteractiveDeployment and validates again after TAR creation.

Upload re-checks size; UploadWithRetry does not refresh URLs or retry when the error is errArchiveTooLarge. Archives at exactly 5 GiB still pass.

Reviewed by Cursor Bugbot for commit dc8ae81. Bugbot is set up for automated code reviews on this repo. Configure here.


Note

The latest commit wraps the errors returned by archiveSizeError with core.MarkExpectedError(..., core.CLIErrorValidation) so oversized-archive failures are classified as expected validation errors (suppressing Sentry noise) rather than unexpected crashes.

Written by Mendral for commit dc8ae81.

@mendral-app

mendral-app Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Interaction Flow

Here's a sequence diagram showing how the size validation gates remote requests across the affected components:

sequenceDiagram
    participant User as User (bl deploy / bl push)
    participant Deployment as Deployment
    participant Archive as Archive (os.Stat)
    participant Config as core.Config
    participant Remote as Remote API (Apply/ImageBuild)
    participant Upload as Upload (presigned PUT)

    User->>Deployment: Run deploy/push command
    Deployment->>Deployment: Package archive (Tar/Zip)
    Deployment->>Archive: ValidateArchiveSize() → os.Stat()
    Archive-->>Deployment: fileInfo.Size()
    Deployment->>Config: IsVolumeTemplate(config.Type)
    Config-->>Deployment: true/false

    alt size > 5 GiB (source code)
        Deployment-->>User: ❌ "reduce via .blaxelignore"
    else size > 5 GiB (volume template)
        Deployment-->>User: ❌ "reduce template directory"
    else size ≤ 5 GiB
        Deployment->>Remote: Send apply / image-build request
        Remote-->>Deployment: presigned upload URL
        Deployment->>Upload: Upload(url)
        Upload->>Archive: os.Stat() (safety re-check)
        alt size > 5 GiB (race/edge)
            Upload-->>Deployment: errArchiveTooLarge
            Deployment->>Deployment: UploadWithRetry skips retry
            Deployment-->>User: ❌ size error (no retry)
        else OK
            Upload-->>Remote: PUT archive bytes
            Remote-->>User: ✅ Deploy/push succeeded
        end
    end
Loading

Flow summary: The PR adds a two-layer size gate — an early check right after archive creation (before any network call), and a redundant safety check inside Upload(). The early check provides user-friendly, context-aware guidance (source-code vs volume-template). UploadWithRetry also short-circuits on errArchiveTooLarge to avoid pointless retries.

Note

Posted by PR Sequence Diagram · Tag @mendral-app with feedback.

@mendral-app

mendral-app Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

🧪 Testing Guide

What this PR addresses

bl deploy and bl push now reject deployment archives larger than 5 GiB before making any remote API calls. For volume templates, it also performs a metadata-only size check (summing regular file sizes) before creating the temporary TAR file, avoiding expensive I/O for obviously oversized directories. Error messages differ based on deployment type: source-code deployments point users to .blaxelignore, while volume-template deployments explain that .blaxelignore doesn't apply.

Steps to reproduce the original issue

  1. Create a volume template directory with files totaling more than 5 GiB (e.g., truncate -s 6G big.bin inside the template dir).
  2. Configure blaxel.toml with type = "volumetemplate" pointing at that directory.
  3. Run bl deploy — previously this would create a multi-GiB temporary TAR and only fail during the upload PUT request, wasting time and disk.
  4. Similarly, for source-code deployments, create a workspace whose ZIP exceeds 5 GiB and run bl deploy or bl push — previously the CLI would attempt the remote apply/image-build request before discovering the upload would fail.

What to verify (expected behavior)

  1. Volume template pre-TAR rejection — With an oversized volume template directory (>5 GiB of regular files excluding blaxel.toml), bl deploy should fail before creating a temporary .blaxel.tar* file. Confirm no temp TAR is left on disk. Error should read:

    archive size exceeds the 5 GB upload limit; reduce the files in the volume template directory (.blaxelignore is not used for volume templates)
    
  2. Source-code post-ZIP validation — With an oversized source ZIP, bl deploy or bl push should fail before any remote API call. Error should read:

    archive size exceeds the 5 GB upload limit; reduce the archive size by adding files or directories to .blaxelignore
    
  3. Exact 5 GiB boundary — An archive of exactly 5 GiB (5×1024³ bytes) should still be accepted and proceed to upload.

  4. No retry on size errorUploadWithRetry should return immediately without refreshing the URL or retrying when the archive is oversized.

  5. Happy path unchanged — Small deployments (both source and volume template) should deploy normally with no behavioral change.

  6. Unit tests pass — Run make test and confirm the new tests (TestVolumeTemplateTarRejectsOversizedFilesBeforeCreatingArchive, TestUploadWithRetryRejectsOversizedArchiveWithoutRetrying, TestValidateArchiveSizeGuidance, TestUploadAllowsArchiveAtSizeLimit) all pass.

Note

Posted by PR Testing Guide · Tag @mendral-app with feedback.

mendral-app[bot]

This comment was marked as outdated.

@mendral-app

mendral-app Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

✅ Linked to Linear issue ENG-1907 — status set to In Progress.

Note

Posted by Linear Issue Enforcer · Tag @mendral-app with feedback.

mendral-app[bot]

This comment was marked as outdated.

@AarjavPatni
AarjavPatni marked this pull request as ready for review August 12, 2026 23:55
mendral-app[bot]

This comment was marked as outdated.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3b5d7ab. Configure here.

Comment thread cli/deploy.go

@mendral-app mendral-app 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.

LGTM

The incremental change correctly wraps errors with MarkExpectedError while preserving the Unwrap chain (classifiedCLIError.Unwrap returns the cause), so errors.Is(err, errArchiveTooLarge) in UploadWithRetry still works. No new issues introduced.

Tag @mendral-app with feedback or questions. View session

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