{"record":{"id":"9266f25dbbcbb25e","repo":"pulumi/pulumi","slug":"esc-request-rate-limit-exceeded","errorCode":null,"errorMessage":"esc: request rate-limit exceeded","messagePattern":"esc: request rate-limit exceeded","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"pkg/cmd/esc/cli/client/client.go","lineNumber":1803,"sourceCode":"\t}\n\n\tresp, err := doWithRetry(pc.httpClient, req, opts.RetryPolicy)\n\tif err != nil {\n\t\t// Don't wrap *apitype.ErrorResponse.\n\t\tif _, ok := err.(*apitype.ErrorResponse); ok {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, fmt.Errorf(\"performing HTTP request: %w\", err)\n\t}\n\n\t// Provide a better error if using an authenticated call without having logged in first.\n\tif resp.StatusCode == 401 && pc.apiToken == \"\" {\n\t\treturn nil, errors.New(\"this command requires logging in; try running `esc login` first\")\n\t}\n\n\t// Provide a better error if rate-limit is exceeded(429: Too Many Requests)\n\tif resp.StatusCode == 429 {\n\t\treturn nil, errors.New(\"esc: request rate-limit exceeded\")\n\t}\n\n\t// For 4xx and 5xx failures, attempt to provide better diagnostics about what may have gone wrong.\n\tif resp.StatusCode >= 400 && resp.StatusCode <= 599 {\n\t\t// 4xx and 5xx responses should be of type ErrorResponse. See if we can unmarshal as that\n\t\t// type, and if not just return the raw response text.\n\t\trespBody, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"API call failed (%s), could not read response: %w\", resp.Status, err)\n\t\t}\n\n\t\treqID := \"\"\n\t\tif resp.StatusCode >= 500 {\n\t\t\treqID = resp.Header.Get(\"X-Pulumi-Request-ID\")\n\t\t}\n\t\treturn nil, decodeError(respBody, resp.StatusCode, opts, reqID)\n\t}\n","sourceCodeStart":1785,"sourceCodeEnd":1821,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/cmd/esc/cli/client/client.go#L1785-L1821","documentation":"The ESC client maps HTTP 429 (Too Many Requests) responses to this fixed error message. The Pulumi Cloud API rate-limits requests, and when the client's request exceeds that limit it surfaces this dedicated error instead of a generic server error.","triggerScenarios":"Any esc client API call when the server returns status 429 — typically issuing many rapid ESC API requests (e.g. bulk environment reads/updates in scripts or CI loops).","commonSituations":"Automation scripts iterating over many environments; CI pipelines polling ESC; retry loops without backoff hammering the API; shared org hitting its quota.","solutions":["Wait and retry the request later (respect the rate limit window)","Add exponential backoff/jitter between API calls in scripts","Batch or cache environment reads instead of calling the API per item","Reduce concurrency in CI jobs that call ESC"],"exampleFix":"// before: tight loop\nfor env := range envs { client.GetEnvironment(ctx, env) }\n// after: backoff\nfor env := range envs {\n    time.Sleep(backoff.Next())\n    client.GetEnvironment(ctx, env)\n}","handlingStrategy":"retry","validationCode":"// Throttle client-side before hitting the API\nlimiter := rate.NewLimiter(rate.Every(200*time.Millisecond), 1)\n_ = limiter.Wait(ctx) // before each esc client call","typeGuard":null,"tryCatchPattern":"// Go: retry with backoff on rate-limit\nvar out *escenv.Environment\nerr := retry.Do(func() error {\n    env, err := client.GetEnvironment(ctx, org, proj, env)\n    if err != nil {\n        if strings.Contains(err.Error(), \"rate-limit exceeded\") {\n            return retry.DelayType(retry.BackOffDelay)(err) // or retryable marker\n        }\n        return retry.Unrecoverable(err)\n    }\n    out = env\n    return nil\n})","preventionTips":["Add backoff and jitter to all ESC API loops","Batch environment reads/writes instead of per-item calls","Limit parallelism in CI jobs that call ESC"],"tags":["rate-limit","http-429","network"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}