{"record":{"id":"057906c95a3fb913","repo":"grafana/k6","slug":"archive-upload-failed-d-s-s","errorCode":null,"errorMessage":"archive upload failed: %d %s: %s","messagePattern":"archive upload failed: (.+?) (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloudapi/provisioning/api.go","lineNumber":120,"sourceCode":"\treq.Header.Set(\"Content-Type\", \"application/x-tar\")\n\treq.ContentLength = int64(len(body))\n\n\tresp, err := c.doWithRetry(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"uploading archive: %w\", err)\n\t}\n\tdefer func() {\n\t\t_, _ = io.Copy(io.Discard, resp.Body)\n\t\t_ = resp.Body.Close()\n\t}()\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\trespBody, readErr := io.ReadAll(resp.Body)\n\t\tif readErr != nil || len(respBody) == 0 {\n\t\t\treturn fmt.Errorf(\"archive upload failed: %d %s\",\n\t\t\t\tresp.StatusCode, http.StatusText(resp.StatusCode))\n\t\t}\n\t\treturn fmt.Errorf(\"archive upload failed: %d %s: %s\",\n\t\t\tresp.StatusCode, http.StatusText(resp.StatusCode), respBody)\n\t}\n\n\treturn nil\n}\n\n// WaitForTestRunReady polls GET /cloud/v6/test_runs/{id} until the\n// backend status becomes \"initializing\" (signalling that k6 can begin\n// local execution). Returns an error if the test run reaches \"aborted\"\n// or \"completed\" first. Cancellable via context. Logs status transitions\n// at Debug level once per change.\n//\n// If pollInterval is <= 0 the defaultWaitPollInterval is used.\nfunc (c *Client) WaitForTestRunReady(ctx context.Context, testRunID int64, pollInterval time.Duration) error {\n\tif pollInterval <= 0 {\n\t\tpollInterval = defaultWaitPollInterval\n\t}\n","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/cloudapi/provisioning/api.go#L102-L138","documentation":"Same rejection path as the empty-body variant, but here the response body was readable and is appended verbatim (internal/cloudapi/provisioning/api.go:119-122). For S3-style storage this is typically an XML error document whose <Code> element names the exact cause - ExpiredToken, AccessDenied, SignatureDoesNotMatch, EntityTooLarge - making this the most diagnostic of the upload failures.","triggerScenarios":"SignatureDoesNotMatch after a proxy or client altered query parameters; ExpiredToken when the upload starts after the presigned window closed; AccessDenied from bucket/IAM policy on the backend; EntityTooLarge when the archive exceeds the bucket or backend limit.","commonSituations":"Corporate proxies normalizing/encoding URLs differently; long-running CI jobs reusing a URL issued minutes earlier; large archives (big bundled assets or many files) exceeding upload limits.","solutions":["Read the <Code> in the appended body: ExpiredToken -> re-run for a fresh URL; SignatureDoesNotMatch -> something altered the URL in transit (bypass the proxy); AccessDenied -> backend/bucket policy, contact cloud support; EntityTooLarge -> shrink the archive","Shrink the archive by removing unnecessary bundled files or using --include-only-env? or k6 archive optimizations; check archive size before upload","Re-run the test - each provisioning issues a fresh presigned URL","If the backend is yours, raise the upload size limit or URL lifetime"],"exampleFix":"# before - bundling a huge dataset into the archive\ncp ./huge-fixtures/** ./   # tens of MB\nk6 cloud run --local-execution script.js   # archive upload failed: 400 ... EntityTooLarge\n\n# after - keep the archive lean; fetch data at runtime\n# (remove fixtures from the bundle)\nk6 cloud run --local-execution script.js","handlingStrategy":"retry","validationCode":null,"typeGuard":"// classify S3-style XML bodies embedded in the error\nfunc uploadErrCode(errMsg string) string {\n    m := regexp.MustCompile(`<Code>([A-Za-z]+)</Code>`).FindStringSubmatch(errMsg)\n    if m == nil {\n        return \"\"\n    }\n    return m[1]\n}","tryCatchPattern":"if err := c.UploadArchive(ctx, url, body); err != nil {\n    switch uploadErrCode(err.Error()) {\n    case \"ExpiredToken\", \"AccessDenied\":\n        // re-run the test for a fresh URL / check backend policy - do not blind-retry this URL\n    case \"SignatureDoesNotMatch\":\n        // URL was altered in transit: fix the proxy path first\n    case \"EntityTooLarge\":\n        // shrink the archive before retrying\n    }\n}","preventionTips":["Keep archives small: exclude datasets and binaries from the tarball; load data at runtime instead","Bypass URL-rewriting proxies for presigned upload hosts","Read the appended body first - it names the exact failure and dictates the fix"],"tags":["cloud","s3","upload","archive","http","provisioning"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}