{"id":"10710e9bf4a171ad","repo":"redis/redis-py","slug":"get-credentials-must-be-implemented","errorCode":null,"errorMessage":"get_credentials must be implemented","messagePattern":"get_credentials must be implemented","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"redis/credentials.py","lineNumber":14,"sourceCode":"import logging\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Callable, Optional, Tuple, Union\n\nlogger = logging.getLogger(__name__)\n\n\nclass CredentialProvider:\n    \"\"\"\n    Credentials Provider.\n    \"\"\"\n\n    def get_credentials(self) -> Union[Tuple[str], Tuple[str, str]]:\n        raise NotImplementedError(\"get_credentials must be implemented\")\n\n    async def get_credentials_async(self) -> Union[Tuple[str], Tuple[str, str]]:\n        logger.warning(\n            \"This method is added for backward compatibility. \"\n            \"Please override it in your implementation.\"\n        )\n        return self.get_credentials()\n\n\nclass StreamingCredentialProvider(CredentialProvider, ABC):\n    \"\"\"\n    Credential provider that streams credentials in the background.\n    \"\"\"\n\n    @abstractmethod\n    def on_next(self, callback: Callable[[Any], None]):\n        \"\"\"\n        Specifies the callback that should be invoked","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/credentials.py#L1-L32","documentation":"Raised as NotImplementedError by CredentialProvider.get_credentials (redis/credentials.py:14). CredentialProvider is the abstract base for pluggable auth (static username/password, EntraID/JWT, etc.); get_credentials() has no default because every real provider must supply credentials differently. Subclassing it without overriding get_credentials() leaves the auth flow unimplemented.","triggerScenarios":"Creating a custom CredentialProvider subclass (or instantiating the base class) and passing it to a Redis client's credential_provider argument; the first time the connection authenticates it calls get_credentials() and hits the stub.","commonSituations":"Writing a custom token/secret-manager provider and forgetting to implement the method; copying a provider example that only overrides the async variant; passing CredentialProvider itself instead of UsernamePasswordCredentialProvider.","solutions":["Override get_credentials() in your subclass to return a (password,) or (username, password) tuple.","If you only need static credentials, use the built-in UsernamePasswordCredentialProvider instead of subclassing.","For async providers, also override get_credentials_async() to avoid the deprecation warning and blocking fallback.","Make get_credentials() abstract with @abstractmethod so the mistake is caught at instantiation, not at first connect."],"exampleFix":"// before\nclass MyProvider(redis.credentials.CredentialProvider):\n    def __init__(self, vault):\n        self.vault = vault\n    # forgot get_credentials\n\n// after\nclass MyProvider(redis.credentials.CredentialProvider):\n    def __init__(self, vault):\n        self.vault = vault\n    def get_credentials(self):\n        token = self.vault.get_token()\n        return (token,)","handlingStrategy":"validation","validationCode":"from redis.credentials import CredentialProvider\nclass MyProvider(CredentialProvider):\n    def get_credentials(self):\n        return ('token',)  # or (username, password)\nprovider = MyProvider()\nassert not isinstance(type(provider).get_credentials, type(CredentialProvider.get_credentials)), \\\n    'get_credentials not overridden'","typeGuard":"from redis.credentials import CredentialProvider\nfrom typing import Any, cast\nimport inspect\n\ndef is_credential_provider_complete(p: Any) -> bool:\n    if not isinstance(p, CredentialProvider):\n        return False\n    # ensure get_credentials is overridden, not the base stub\n    owner = vars(type(p))\n    if 'get_credentials' not in owner:\n        # check MRO for a concrete (non-base) override\n        for klass in type(p).__mro__[1:-1]:\n            if 'get_credentials' in vars(klass) and klass is not CredentialProvider:\n                return True\n        return False\n    return True","tryCatchPattern":null,"preventionTips":["Make get_credentials a @abstractmethod so the mistake fails at instantiation.","Reuse UsernamePasswordCredentialProvider for static credentials instead of subclassing.","Override get_credentials_async() for async clients to avoid the blocking fallback.","Add a unit test that calls get_credentials() on any new provider subclass."],"tags":["auth","credentials","notimplemented","subclassing"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}