Running a load test scenario to validate script assignment throughput before our next major release. The goal is to simulate 150 concurrent agents logging in and triggering the initial script fetch via the Platform API. Using JMeter 5.6.2 with the HTTP Request Defaults set to use keep-alive. The target endpoint is GET /api/v2/scripts/{scriptId}.
When the thread count stays below 50, everything works fine. Response times are under 200ms. But as soon as I ramp up to 100 concurrent threads, about 40% of the requests start failing with a 400 Bad Request. The response body is just {"code":"bad_request","message":"Invalid script definition"}. This is confusing because the script itself hasn’t changed. It is a simple linear script with a greeting and a transfer step. No complex conditions or variables. The script ID is valid and active in the UI.
I checked the network traces. The requests are hitting the same region endpoint. No timeouts. The 400s happen almost instantly. It feels like the API gateway or the script service is rejecting the payload based on some concurrency constraint or a malformed parameter that only appears under load. I have verified the script JSON in the DB looks correct.
Here is what I have tried so far:
- Reduced the JMeter ramp-up time to 30 seconds to see if a softer load helps, but the 400s still appear once the concurrent thread count hits roughly 80.
- Tried using different script IDs from different tenants to rule out a specific script corruption issue, but the error persists across all valid script IDs under high concurrency.
The environment is Genesys Cloud US-East. the platform internals, so I might be missing a basic rate limit or caching behavior. Is there a known limit on simultaneous script definition fetches? Or could this be related to how the script service handles concurrent serialization of the script tree? Any pointers on where to look for the root cause of these 400s would be appreciated. I have attached the JMeter CSV export showing the status codes.
make sure you check the api rate limits for script endpoints. they are often stricter than recording apis. if you hit 400, it is usually payload or quota related. try adding exponential backoff in jmeter. also verify the script id is valid for all concurrent threads.
Yep, this is a known issue…
Running a load test scenario to validate script assignment throughput before our next major release. The goal is to simulate 150 concurrent agents logging in and triggering the initial script fetch via the Platform API. Using JMeter 5.6.2 with the HTTP Request Defaults set to use keep-alive. The target endpoint is GET /api/v2/scripts/{scriptId}. When the thread count stays below 50, everything works fine. Response times are under 200ms. But as soon as I ramp up to 100 conc
The suggestion regarding rate limits is accurate, but the specific nature of the 400 Bad Request indicates a payload or header validation failure rather than a simple 429 Too Many Requests quota issue. In high-concurrency scenarios, the platform often rejects requests if the Authorization header is malformed or if the Accept header is missing or incorrect.
For script endpoints, the system expects strict adherence to the REST API contract. When simulating 150 concurrent users, ensure that each thread is using a unique, valid OAuth token. Reusing a single token across multiple threads can trigger session conflicts, resulting in a 400 error due to invalid session state.
Additionally, verify that the scriptId parameter is correctly URL-encoded. If the script ID contains special characters, JMeter might not encode them properly under load, causing the server to reject the request.
Here is a recommended JMeter configuration adjustment:
<!-- Ensure each thread has a unique token -->
<HTTPSamplerProxy>
<stringProp name="HTTPsampler.Arguments"></stringProp>
<stringProp name="HTTPsampler.path">/api/v2/scripts/${scriptId}</stringProp>
<stringProp name="HTTPsampler.method">GET</stringProp>
<stringProp name="HTTPsampler.headers">
Accept: application/json
Authorization: Bearer ${unique_token}
</stringProp>
</HTTPSamplerProxy>
Implementing exponential backoff, as suggested, will help mitigate the load, but correcting the header validation is the primary fix for the 400 errors.
This is actually a known issue…
The 400 Bad Request here is usually not a payload error but a concurrent state mutation conflict. When JMeter fires 100+ threads simultaneously, the platform locks the script resource for versioning. The API rejects writes if the ETag header in the request does not match the current server state.
Check your JMeter HTTP Header Manager. Ensure you are sending the correct If-Match header with the latest version ID. If you are only reading, ensure no hidden POST/PUT actions are triggered by the login sequence.
Also, verify the script is not in a draft state during the test. Drafts have stricter concurrency controls.
Reference: Genesys Cloud API Versioning and Concurrency Limits
Fix the header handling in the test plan. The 400 will disappear.
Check your JMeter Thread Group configuration for “Ramp-Up Period” settings. The suggestion above regarding ETags is technically accurate for write operations, but the endpoint in question is a GET request for script fetching. A 400 Bad Request on a GET usually indicates a malformed URI or an invalid query parameter in the burst, not a version conflict.
Running a load test scenario to validate script assignment throughput before our next major release. The goal is to simulate 150 concurrent agents logging in and triggering the initial script fetch via the Platform API. Using JMeter 5.6.2 with the HTTP Request Defaults set to use keep-alive. The target endpoint is GET /api/v2/scripts/{scriptId}.
In my recent load testing with 200 concurrent users, I observed that when the ramp-up is set to 0 seconds, all threads fire simultaneously. This creates a sudden spike in WebSocket connections and HTTP requests that exceeds the immediate capacity of the API gateway’s parser. The gateway returns a 400 because it cannot parse the rapid-fire stream of headers correctly, mistaking it for a malformed request sequence.
The fix is simple. Change the Ramp-Up Period to match the Thread Count. For 150 threads, set Ramp-Up to 150 seconds. This ensures one new thread starts every second, smoothing the load curve.
Also, verify the scriptId parameter. If you are using a CSV Data Set Config, ensure the file is looped correctly. If the script ID is null or empty for any thread, the API returns a 400. Add a simple “If Controller” in JMeter to check if ${scriptId} is not empty before firing the request.
<!-- JMeter If Controller Condition -->
${!__isEmpty(${scriptId})}
This prevents the API from receiving invalid requests and helps isolate true capacity issues from configuration errors in the test plan.