Skip to content

@actions/artifact: BlobClient upload fails with "Bad Request" through HTTPS proxy — no proxy transport configured #2377

@savitha-qs

Description

@savitha-qs

Description

When a GitHub Actions self-hosted runner is configured with HTTPS_PROXY, the upload-artifact action fails with Error: Bad Request during the blob upload step. The @actions/artifact package creates a BlobClient from @azure/storage-blob without configuring proxy transport, causing the Azure SDK's HTTP pipeline to handle the CONNECT tunnel incorrectly.

Root cause

In packages/artifact/src/internal/upload/blob-upload.ts:

const blobClient = new BlobClient(authenticatedUploadURL)
const blockBlobClient = blobClient.getBlockBlobClient()

The BlobClient is created with only a URL — no StoragePipelineOptions with proxy configuration. The @azure/storage-blob SDK creates its own internal HTTP pipeline which may not correctly handle HTTPS CONNECT tunnels even though HTTPS_PROXY is set in the environment.

Suggested fix

Pass pipeline options with proxy configuration:

import { ProxyPolicy } from '@azure/core-rest-pipeline'

const blobClient = new BlobClient(authenticatedUploadURL, undefined, {
  proxyOptions: {
    host: process.env.HTTPS_PROXY || process.env.https_proxy,
  }
})

Or use newPipeline with the StorageSharedKeyCredential and configure the proxy in the pipeline options.

Evidence

Proxy logs confirm the CONNECT tunnel succeeds but the upload stalls:

CONNECT productionresultssa6.blob.core.windows.net:443 → status=200 (ALLOWED)
  requestSize=17259    (only ~17 KB sent)
  responseSize=8828    (error response)
  latency=74.999634s   (stalled for 75 seconds)
  user-agent: azsdk-net-Storage.Blobs/12.27.0 (.NET 8.0.25; Ubuntu 24.04.4 LTS)

Curl and Python upload 1 MB to the same blob endpoint through the same proxy in <1 second:

curl PUT 1MB to blob → HTTP 409 in 0.3s
Python PUT 1MB to blob → HTTP 409 in 0.6s

Standalone .NET HttpClient.PutAsync() also works fine (1.1s) — the issue is in how the Azure SDK BlobClient is instantiated without proxy configuration.

Workflow output

Run actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
With the provided path, there will be 1 file uploaded
Artifact name is valid!
Root directory input is valid!
Uploading artifact: trivy-scan-results--skaffold-build-24347418057-1-1776089109.zip
Beginning upload of artifact content to blob storage
Error: Bad Request

Related

  • actions/runner#4351 — same root cause in the runner's .NET ResultsHttpClient.cs which also creates BlobClient without proxy transport. The runner's step log/summary/diagnostic uploads stall in the same way.

Environment

  • Runner: GitHubActionsRunner-linux-x64/2.333.1 (self-hosted on GKE via actions-runner-controller v0.13.1)
  • Action: actions/upload-artifact@v4 (SHA bbbca2ddaa5d8feaa63e36b76fdaad77386f024f)
  • Package: @actions/artifact v6.2.0 → @azure/storage-blob v12.30.0
  • Proxy: GCP Secure Web Proxy (HTTPS forward proxy, CONNECT tunnel, no TLS inspection)
  • Config: HTTPS_PROXY=http://<proxy-ip>:443
  • Platform: Ubuntu 24.04.4 LTS on GKE

Workaround

Add .blob.core.windows.net to NO_PROXY:

NO_PROXY=.blob.core.windows.net

This bypasses the proxy for Azure Blob traffic, but defeats the purpose of hostname-based egress control through the proxy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions