{"record":{"id":"65eea32e0f851a92","repo":"openai/openai-python","slug":"x-509-workload-identity-cannot-be-changed-after-cl","errorCode":null,"errorMessage":"X.509 workload identity cannot be changed after client construction","messagePattern":"X\\.509 workload identity cannot be changed after client construction","errorType":"exception","errorClass":"OpenAIError","httpStatus":null,"severity":"error","filePath":"src/openai/_client.py","lineNumber":537,"sourceCode":"    def qs(self) -> Querystring:\n        return Querystring(array_format=\"brackets\")\n\n    def _send_with_auth_retry(\n        self,\n        request: httpx2.Request,\n        *,\n        stream: bool,\n        retried: bool = False,\n        **kwargs: Unpack[HttpxSendArgs],\n    ) -> httpx2.Response:\n        used_access_token: str | None = None\n        request_is_replayable = False\n        x509_auth = self._workload_identity_auth\n\n        if x509_auth is not None:\n            if isinstance(x509_auth, SyncX509WorkloadIdentityAuth):\n                if x509_auth.workload_identity != self.workload_identity:\n                    raise OpenAIError(\"X.509 workload identity cannot be changed after client construction\")\n                validate_x509_api_url(request.url, expected_origin=self.base_url)\n                validate_x509_request_authority(request)\n                validate_x509_api_credentials(request)\n            if x509_auth._follow_redirects is not None:\n                kwargs[\"follow_redirects\"] = x509_auth._follow_redirects\n            authorization = request.headers.get(\"Authorization\")\n            if authorization == f\"Bearer {WORKLOAD_IDENTITY_API_KEY_PLACEHOLDER}\":\n                used_access_token = (\n                    x509_auth.get_token_for_request(request)\n                    if isinstance(x509_auth, SyncX509WorkloadIdentityAuth)\n                    else x509_auth.get_token()\n                )\n                request.headers[\"Authorization\"] = f\"Bearer {used_access_token}\"\n                request_is_replayable = x509_auth._can_retry_request(request)\n\n        if isinstance(x509_auth, SyncX509WorkloadIdentityAuth):\n            response = x509_auth.send_api_request(\n                request,","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/_client.py#L519-L555","documentation":"The X.509 auth handler snapshots the workload identity at client construction. If `client.workload_identity` is later mutated/replaced so it no longer equals the captured identity, `_send_with_auth_retry` refuses the request because cert rotation outside the client could break mTLS mid-flight.","triggerScenarios":"Assigning `client.workload_identity = new_identity` after construction; mutating the identity dict in place between requests; sharing one client across rotation code that swaps identities.","commonSituations":"Certificate-rotation logic that updates the client attribute instead of rebuilding the client; test harnesses mutating state; multi-tenant code trying to reuse one client with different identities.","solutions":["Build a new client when rotating: `client = OpenAI(workload_identity=new_identity)`","Remove any code that writes `client.workload_identity` post-construction","Scope one client per identity in multi-tenant setups"],"exampleFix":"# before\nclient.workload_identity = rotated_identity\nresp = client.models.list()\n\n# after\nclient = OpenAI(workload_identity=rotated_identity)\nresp = client.models.list()","handlingStrategy":"validation","validationCode":"# treat clients as immutable; on rotation rebuild\nif new_identity is not client.workload_identity:\n    client = OpenAI(workload_identity=new_identity, base_url=client.base_url)","typeGuard":null,"tryCatchPattern":"try:\n    resp = client.models.list()\nexcept OpenAIError as e:\n    if 'cannot be changed after client construction' in str(e):\n        client = OpenAI(workload_identity=client.workload_identity)  # rebuild\n        resp = client.models.list()\n    else:\n        raise","preventionTips":["Never assign to client.workload_identity after construction","Structure cert rotation as: build new client, then atomically swap the reference","One client per identity/tenant"],"tags":["auth","x509","workload-identity","immutability","rotation"],"backgroundTag":"credential-rotation-error","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}