grafana/k6 · error
upload archive: %w
Error message
upload archive: %w
What it means
Client.ProvisionLocalExecution (internal/cloudapi/provisioning/provision.go:93) wraps Client.UploadArchive failing to PUT the pre-serialised archive bytes to the presigned S3 URL. The presigned URL carries auth in query parameters; failures are either transport-level (wrapped as 'uploading archive') or non-2xx from S3 — most often 403 (expired or mangled presigned URL) or 400 (signature/content mismatch).
Source
Thrown at internal/cloudapi/provisioning/provision.go:93
archiveBytes = buf.Bytes()
}
sleReq := StartLocalExecutionRequest{
Options: params.Options,
MaxVUs: params.MaxVUs,
TotalDuration: params.TotalDuration,
ArchiveSize: archiveSize,
}
sleResp, err := c.StartLocalExecution(ctx, loadTestID, sleReq)
if err != nil {
return nil, fmt.Errorf("start local execution: %w", err)
}
switch {
case params.Archive != nil && sleResp.ArchiveUploadURL != nil:
if err := c.UploadArchive(ctx, *sleResp.ArchiveUploadURL, archiveBytes); err != nil {
return nil, fmt.Errorf("upload archive: %w", err)
}
case params.Archive != nil && sleResp.ArchiveUploadURL == nil:
// We had an archive to upload but the API returned no upload URL;
// proceed without uploading rather than failing the run.
c.logger.Warn("archive present but provisioning API returned no upload URL; skipping archive upload")
}
if err := c.WaitForTestRunReady(ctx, sleResp.TestRunID, params.PollInterval); err != nil {
return nil, fmt.Errorf("wait for test run ready: %w", err)
}
return &ProvisionResult{
TestRunID: sleResp.TestRunID,
TestRunDetailsPageURL: sleResp.TestRunDetailsPageURL,
RuntimeConfig: sleResp.RuntimeConfig,
}, nil
}
View on GitHub (pinned to 93accf6570)
Solutions
- Re-provision the run to obtain a fresh presigned URL and retry promptly
- Reduce archive size (prune includes, avoid bundling dependencies) to fit the upload window
- Ensure no proxy/agent modifies the request URL or query string; bypass it for the S3 host
- Verify system clock synchronization (NTP) on the runner
- Check the wrapped status text — 403 points at expiry/signature, 5xx at S3 health
Defensive patterns
Strategy: retry
Validate before calling
if params.Archive != nil {
const maxSaneUpload = 1 << 30 // 1 GiB comfort ceiling
if archiveSize > maxSaneUpload {
return fmt.Errorf("archive %d bytes too large for reliable upload; prune or use --no-archive-upload", archiveSize)
}
} Type guard
func isUploadFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "upload archive")
} Try / catch
res, err := client.ProvisionLocalExecution(ctx, params)
if err != nil {
if isUploadFailure(err) {
// re-provision to mint a fresh presigned URL, then retry promptly
}
return err
} Prevention
- Upload immediately after start_local_execution returns — presigned URLs expire
- Keep archives small; exclude dependencies and build output
- Ensure proxies don't rewrite URLs; sync system clocks via NTP
- Retry by re-provisioning, never by reusing a possibly-expired URL
When it happens
Trigger: Upload of a very large archive exceeding the presigned URL's validity window; a proxy stripping or re-encoding query parameters; clock skew invalidating the signature; connection timeouts on slow links; any non-2xx S3 status.
Common situations: Corporate proxies rewriting URLs; huge archives on constrained uplinks; host clock drift; retries after long provisioning delays reusing a stale URL.
Related errors
- uploading archive: %w
- archive upload failed: %d %s
- archive upload failed: %d %s: %s
- uploading test: %w
- missing presigned url in response body
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/e37cf801dbf09aab.
Report an issue: GitHub.