{"record":{"id":"5a2729a1934f7817","repo":"PrefectHQ/fastmcp","slug":"invalid-client-5a2729","errorCode":"invalid_client","errorMessage":"invalid_client: Client ID is required","messagePattern":"invalid_client: Client ID is required","errorType":"error_code","errorClass":"AuthorizeError","httpStatus":400,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/providers/in_memory.py","lineNumber":135,"sourceCode":"                # or if params.redirect_uri is None and client has a default.\n                # However, the AuthorizationHandler handles the primary validation.\n                pass  # Let's assume AuthorizationHandler did its job.\n        except Exception as e:  # Replace with specific validation error if client.validate_redirect_uri existed\n            raise AuthorizeError(\n                error=\"invalid_request\", error_description=\"Invalid redirect_uri.\"\n            ) from e\n\n        auth_code_value = f\"test_auth_code_{secrets.token_hex(16)}\"\n        expires_at = time.time() + DEFAULT_AUTH_CODE_EXPIRY_SECONDS\n\n        # Ensure scopes are a list\n        scopes_list = params.scopes if params.scopes is not None else []\n        if client.scope:  # Filter params.scopes against client's registered scopes\n            client_allowed_scopes = set(client.scope.split())\n            scopes_list = [s for s in scopes_list if s in client_allowed_scopes]\n\n        if client.client_id is None:\n            raise AuthorizeError(\n                error=\"invalid_client\", error_description=\"Client ID is required\"\n            )\n        auth_code = AuthorizationCode(\n            code=auth_code_value,\n            client_id=client.client_id,\n            redirect_uri=params.redirect_uri,\n            redirect_uri_provided_explicitly=params.redirect_uri_provided_explicitly,\n            scopes=scopes_list,\n            expires_at=expires_at,\n            code_challenge=params.code_challenge,\n            # code_challenge_method is assumed S256 by the framework\n        )\n        self.auth_codes[auth_code_value] = auth_code\n\n        return construct_redirect_uri(\n            str(params.redirect_uri), code=auth_code_value, state=params.state\n        )\n","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/providers/in_memory.py#L117-L153","documentation":"Just before building the AuthorizationCode, authorize() asserts that the client has a non-None client_id, since the code must record which client it was issued to. A Client whose client_id is None triggers AuthorizeError('invalid_client', 'Client ID is required').","triggerScenarios":"Calling authorize() with a Client object constructed without a client_id (client_id=None) — the earlier `client.client_id not in self.clients` check passes only if None is somehow a key, so this typically follows partially-populated client objects in tests or handlers.","commonSituations":"Test fixtures building Client dataclasses with defaults; a token/authorization handler losing the id when mapping between metadata and Client; deserialization dropping an absent client_id field.","solutions":["Set client_id on the Client before calling authorize","Verify registration flow so the Client passed downstream carries the registered id","Add an assertion or guard in your own code: `assert client.client_id is not None` before authorization calls"],"exampleFix":"// before\nclient = Client(redirect_uris=[...])  # client_id defaults to None\nprovider.authorize(client, params)\n// after\nclient = Client(client_id=\"app-1\", redirect_uris=[...])\nprovider.authorize(client, params)","handlingStrategy":"type-guard","validationCode":"if client.client_id is None:\n    raise ValueError(\"Client must have client_id before authorize()\")\nprovider.authorize(client, params)","typeGuard":"def has_client_id(client) -> bool:\n    return isinstance(client.client_id, str) and bool(client.client_id)","tryCatchPattern":"try:\n    redirect = provider.authorize(client, params)\nexcept AuthorizeError as e:\n    if e.error == \"invalid_client\":\n        logger.error(\"Client object missing client_id: %s\", client)","preventionTips":["Construct Client objects via a factory that requires client_id","Add client_id presence assertions in test fixtures","Never deserialize authorization state into Client objects without validating the id"],"tags":["oauth","client-id","authorization"],"backgroundTag":"missing-client-id","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}