{"record":{"id":"208bffc99846f2b2","repo":"apache/seatunnel","slug":"stripe-api-rate-limit-reached-retry-after","errorCode":null,"errorMessage":"Stripe API rate limit reached, retry {}/{} after {} ms","messagePattern":"Stripe API rate limit reached, retry (.+?)/(.+?) after (.+?) ms","errorType":"console","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-http/connector-http-stripe/src/main/java/org/apache/seatunnel/connectors/seatunnel/stripe/source/StripeSourceReader.java","lineNumber":171,"sourceCode":"\n    private HttpResponse executeWithRateLimitRetry() throws Exception {\n        int retries = 0;\n        while (true) {\n            HttpResponse response =\n                    httpClient.execute(\n                            sourceParameter.getUrl(),\n                            sourceParameter.getMethod().getMethod(),\n                            sourceParameter.getHeaders(),\n                            sourceParameter.getParams(),\n                            sourceParameter.getBody(),\n                            sourceParameter.isKeepParamsAsForm());\n            if (response.getCode() != HTTP_TOO_MANY_REQUESTS\n                    || retries >= sourceParameter.getRateLimitMaxRetries()) {\n                return response;\n            }\n            retries++;\n            long backoffMillis = calculateBackoffMillis(retries);\n            log.warn(\n                    \"Stripe API rate limit reached, retry {}/{} after {} ms\",\n                    retries,\n                    sourceParameter.getRateLimitMaxRetries(),\n                    backoffMillis);\n            try {\n                sleeper.sleep(backoffMillis);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new HttpConnectorException(\n                        HttpConnectorErrorCode.REQUEST_FAILED,\n                        \"Interrupted while waiting to retry Stripe request\",\n                        e);\n            }\n        }\n    }\n\n    @VisibleForTesting\n    long calculateBackoffMillis(int retryNumber) {","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-http/connector-http-stripe/src/main/java/org/apache/seatunnel/connectors/seatunnel/stripe/source/StripeSourceReader.java#L153-L189","documentation":"StripeSourceReader wraps API calls in executeWithRateLimitRetry. When the Stripe API returns HTTP 429 (Too Many Requests) and retries remain, it logs this warning, computes an exponential backoff delay, sleeps, and retries the request. It is an informational retry notice, not a fatal error; it becomes an error only when rateLimitMaxRetries is exhausted, at which point the 429 response is returned to the caller.","triggerScenarios":"Stripe API responds with HTTP status 429 while retries < rateLimitMaxRetries inside executeWithRateLimitRetry (invoked from the source reader's response handling).","commonSituations":"High-volume historical backfills exceeding Stripe's per-key rate limits; multiple concurrent SeaTunnel jobs sharing one Stripe API key; rateLimitMaxRetries configured too low for sustained 429s.","solutions":["Increase the rate-limit max retries option so bursts of 429s are absorbed.","Reduce source read parallelism or split size to lower request rate.","Check calculateBackoffMillis settings/jitter to spread requests.","Use a dedicated Stripe API key for the sync job to avoid contention with other consumers.","Handle the returned 429 response after exhaustion — schedule the job during off-peak hours or in smaller windows."],"exampleFix":"// before\nsourceParameter.getRateLimitMaxRetries() == 3\n// after\n// raise retries and lower parallelism to stay under Stripe limits\n\"rate_limit_max_retries\" = 10, parallelism = 1","handlingStrategy":"retry","validationCode":"// ensure sane retry config before job start\nif (rateLimitMaxRetries <= 0 || rateLimitMaxRetries > 20) {\n    throw new IllegalArgumentException(\"rate_limit_max_retries must be in (0, 20]\");\n}","typeGuard":null,"tryCatchPattern":"Response response = executeWithRateLimitRetry(request);\nif (response.getCode() == 429) {\n    // retries exhausted: back off long-term and re-run later\n    throw new IOException(\"Stripe rate limit persists after max retries\");\n}","preventionTips":["Set rate_limit_max_retries generously (e.g., 10+) for Stripe sources.","Run one job per API key; avoid sharing keys across concurrent jobs.","Schedule large historical backfills off-peak.","Keep source parallelism low (Stripe limits are per-key, not per-worker).","Alert on recurring 'Stripe API rate limit reached' warnings to catch sustained 429s early."],"tags":["http","rate-limit","retry","api"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}