-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Bug: ChangeRequestMicroClient.list() Mutates Class Variable Causing URL Template to Grow Indefinitely
Description
The list() method in ChangeRequestMicroClient mutates the shared class variable _endpoint, causing the URL template to grow with every call. After ~25 calls in a Prefect environment (used for managing split production environments), requests start failing with HTTP 414 (URI Too Long). When tested locally, failures occur after 100+ calls with either 414 or 431 (Request Header Fields Too Large) errors.
Root Cause
In microclients/change_request_microclient.py, _endpoint is defined as a class variable (line 10), but the list() method (lines 72–77) mutates it directly:
if(environment_id!=None):
self._endpoint['list_next']['url_template'] = self._endpoint['list_next']['url_template'] + "&environmentId={environmentId}"
self._endpoint['list_initial']['url_template'] = self._endpoint['list_initial']['url_template'] + "&environmentId={environmentId}"
if(status!=None):
self._endpoint['list_next']['url_template'] = self._endpoint['list_next']['url_template'] + "&status={status}"
self._endpoint['list_initial']['url_template'] = self._endpoint['list_initial']['url_template'] + "&status={status}"Because _endpoint is shared across all instances, each invocation appends query parameters again, causing exponential growth of the URL template.
Impact
- After ~25 consecutive
list()calls, requests fail with HTTP 414 in a Prefect environment - Locally, failures occur after ~100–120 calls with 414 or 431
- Affects any code that calls
change_requests.list()repeatedly - The mutation persists for the lifetime of the class, impacting all future instances
Reproduction Steps
from splitapiclient.main import get_client
client = get_client({"apikey": "your_api_key"})
ENV_ID = "your_environment_id"
# After ~25 iterations, the endpoint URL template becomes extremely long
for i in range(30):
cr = client.change_requests.list(environment_id=ENV_ID, status="REQUESTED")
print(f"Call {i+1}: {len(client.change_requests._endpoint['list_initial']['url_template'])} chars")Note: Depending on network configuration, the error may require ~120 iterations to reproduce.
After multiple calls, _endpoint['list_initial']['url_template'] looks like:
changeRequests?limit=100&environmentId={environmentId}&status={status}&environmentId={environmentId}&status={status}&environmentId={environmentId}&status={status}...
Expected Behavior
The URL template should remain constant. Query parameters should be passed via the HTTP client's parameter mechanism, not by mutating the template string.
Environment
- Python version: 3.13 (also observed across 3.x)
splitapiclientversion: 3.5.6- Production environment with high-frequency API calls
Additional Context
This is a critical production issue that causes failures after a relatively small number of calls. A proper fix should ensure that endpoint configuration is immutable or safely scoped per instance to avoid shared state mutations.
| self._endpoint['list_next']['url_template'] = self._endpoint['list_next']['url_template'] + "&environmentId={environmentId}" |
| _endpoint = { |