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

  1. Re-provision the run to obtain a fresh presigned URL and retry promptly
  2. Reduce archive size (prune includes, avoid bundling dependencies) to fit the upload window
  3. Ensure no proxy/agent modifies the request URL or query string; bypass it for the S3 host
  4. Verify system clock synchronization (NTP) on the runner
  5. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/e37cf801dbf09aab. Report an issue: GitHub.