FastAPI’s dependency injection system is failing because it’s unable to resolve a dependency to the expected type, leading to runtime errors.

The most common culprit is a mismatch between the type annotation in your dependency function’s signature and the type of the object actually being provided. FastAPI uses these annotations to match consumers with providers.

Common Causes and Fixes

  1. Incorrect Type Annotation on the Dependency Provider:

    • Diagnosis: Review the type hint on the function or class that provides the dependency.
      # Incorrect:
      def get_db():
          return DatabaseConnection() # No type hint
      
      # Correct:
      from my_database import DatabaseConnection
      
      def get_db() -> DatabaseConnection:
          return DatabaseConnection()
      
    • Fix: Ensure the return type annotation of the provider function accurately reflects the type of object it returns.
    • Why it works: FastAPI inspects these type hints to build its dependency graph. An accurate hint allows it to correctly identify the dependency when requested.
  2. Incorrect Type Annotation on the Consumer:

    • Diagnosis: Check the type hint on the path operation function (or another dependency) that consumes the dependency.
      # Incorrect:
      @app.get("/items/")
      async def read_items(db: SomeOtherType): # Expected DatabaseConnection
          # ... use db ...
          pass
      
      # Correct:
      from my_database import DatabaseConnection
      
      @app.get("/items/")
      async def read_items(db: DatabaseConnection):
          # ... use db ...
          pass
      
    • Fix: The parameter in the consuming function must have a type annotation that matches what the provider is designed to supply.
    • Why it works: This is how FastAPI knows which provider to inject into which consumer; the annotations must align.
  3. Circular Dependencies:

    • Diagnosis: If DependencyA depends on DependencyB, and DependencyB depends on DependencyA, FastAPI cannot resolve either. You’ll often see a RuntimeError or a RecursionError if the resolution process goes too deep.
      # Example of circular dependency
      def get_service_a(service_b: ServiceB) -> ServiceA:
          return ServiceA(service_b)
      
      def get_service_b(service_a: ServiceA) -> ServiceB:
          return ServiceB(service_a)
      
      app.dependency_overrides[ServiceA] = get_service_a
      app.dependency_overrides[ServiceB] = get_service_b
      
    • Fix: Refactor your code to break the cycle. This might involve introducing a third, more fundamental dependency that both A and B can depend on, or merging functionality.
    • Why it works: Dependency injection requires a directed acyclic graph (DAG). Cycles break this structure, preventing a clear resolution path.
  4. dependency_overrides Mismatch:

    • Diagnosis: If you’re using app.dependency_overrides, the type annotation on the overridden dependency’s consumer must match the type annotation on the overriding function’s return value.
      # Incorrect override:
      class MockDB:
          pass
      
      def get_mock_db() -> MockDB:
          return MockDB()
      
      @app.get("/test/")
      async def test_endpoint(db: DatabaseConnection): # Expects DatabaseConnection
          pass
      
      app.dependency_overrides[DatabaseConnection] = get_mock_db # Provides MockDB
      
    • Fix: Ensure the type hint in the consumer (db: DatabaseConnection) matches the return type hint of the override function (-> MockDB in this broken example, which should be -> DatabaseConnection).
      # Correct override:
      class MockDB:
          pass
      
      def get_mock_db() -> DatabaseConnection: # Return type must match consumer's expectation
          return MockDB()
      
      @app.get("/test/")
      async def test_endpoint(db: DatabaseConnection):
          pass
      
      app.dependency_overrides[DatabaseConnection] = get_mock_db
      
    • Why it works: Overrides are treated as direct replacements. FastAPI expects the replacement to satisfy the original type contract.
  5. Using Abstract Base Classes (ABCs) or Protocols Without Proper Implementation:

    • Diagnosis: If your dependency is type-hinted as an ABC or a typing.Protocol, the actual object provided must correctly implement that abstract interface.
      from typing import Protocol
      
      class MyProtocol(Protocol):
          def do_something(self) -> str:
              ...
      
      class ActualImplementation:
          def do_something(self) -> str:
              return "hello"
      
      # Incorrect:
      def get_my_protocol() -> MyProtocol: # ActualImplementation doesn't *explicitly* inherit MyProtocol
          return ActualImplementation()
      
      # Correct (if ActualImplementation truly conforms):
      def get_my_protocol() -> MyProtocol:
          return ActualImplementation() # Python's structural typing handles this at runtime if methods match
      
      # More explicit if needed:
      class ExplicitImplementation(MyProtocol):
          def do_something(self) -> str:
              return "hello"
      
      def get_my_protocol_explicit() -> MyProtocol:
          return ExplicitImplementation()
      
    • Fix: Ensure the class providing the dependency has methods and attributes matching the signature defined in the ABC or Protocol. Python’s structural typing (duck typing) will often handle this, but explicit inheritance can sometimes clarify intent or resolve subtle issues.
    • Why it works: FastAPI relies on type hints for static analysis and runtime checks. If the provided object doesn’t "quack like a duck" (i.e., have the required methods/attributes), the type check fails.
  6. Mismatched Generic Types:

    • Diagnosis: When dealing with generic types (e.g., List[str], Optional[User]), ensure the generic arguments align.
      from typing import List, Optional
      
      # Incorrect:
      def get_string_list() -> List[int]: # Expects List[int]
          return ["a", "b", "c"] # Provides List[str]
      
      # Correct:
      def get_string_list() -> List[str]: # Expects List[str]
          return ["a", "b", "c"]
      
    • Fix: Double-check that the type within the generic (e.g., str in List[str]) matches the actual type of the elements in the list, dictionary values, or the optional object.
    • Why it works: Type checkers and FastAPI’s dependency system need to know the precise shape of the data, including the types of elements within collections or the specific type within an Optional.

You’ll likely encounter a TypeError: '...' object is not callable or similar, indicating that FastAPI tried to use an object as a function or constructor because its type couldn’t be resolved correctly.

Want structured learning?

Take the full Fastapi course →