What happens if I forget to register a dependency in EK9?

← Dependency Injection · Ref: Q230

If you forget to register a dependency, the EK9 compiler reports a compile-time error identifying the unsatisfied injection point. Your code will not compile until every injection field has a matching registration.

COMPILE-TIME VS RUNTIME

In Java Spring, forgetting an @Bean produces NoSuchBeanDefinitionException at runtime, potentially minutes into application startup. In EK9, the compiler catches this immediately during compilation.

WHAT THE ERROR TELLS YOU

The compiler identifies:
- The component or program with the unsatisfied injection field
- The type that was expected to be registered
- The application definition where the registration is missing
This gives you everything needed to fix the problem in seconds.

COMPLETENESS CHECK

The compiler walks every injection field in every component and program linked to an application. For each '!' field, it verifies a matching 'register X() as Y' exists where Y matches the field type.

WORKING EXAMPLE

The code below shows a complete, correctly wired application. All three components are registered, and the program's injection point is satisfied. If any registration were removed, the compiler would report the error before any code runs.

See Q111 for component basics. See Q227 for compile-time validation. See Q228 for registration ordering.

See Q111 for components. See Q227 for compile-time DI. See Q228 for registration ordering.

Example

defines module qa.di.missing

  defines component

    Cache as abstract
      get() as abstract
        -> key as String
        <- value as String?

      default operator ?

    InMemoryCache is Cache
      override get()
        -> key as String
        <- value as String: "cached:" + key

      default operator ?

    Repository as abstract
      find() as abstract
        -> id as Integer
        <- result as String?

      default operator ?

    CachedRepository is Repository
      cache as Cache!

      override find()
        -> id as Integer
        <- result <- String()
        result: cache.get("item-" + $id)

      default operator ?

    Controller as abstract
      handle() as abstract
        -> request as String
        <- response as String?

      default operator ?

    ItemController is Controller
      repo as Repository!

      override handle()
        -> request as String
        <- response <- String()
        response: repo.find(1)

      default operator ?

  defines application

    CompleteApp
      // All three registrations present - compiler verifies completeness
      register InMemoryCache() as Cache
      register CachedRepository() as Repository
      register ItemController() as Controller

  defines program

    MissingRegDemo() with application of CompleteApp
      stdout <- Stdout()

      // === ALL REGISTRATIONS SATISFIED ===

      controller as Controller!

      response <- controller.handle("/items/1")
      stdout.println(response)

      stdout.println("Every injection point satisfied at compile time")

Common mistakes

E08210 — Removing the Cache registration leaves CachedRepository's injection field 'cache as Cache!' unsatisfied. The compiler rejects programs where any injection point lacks a matching registration. See ek9 -h E08210 for details.

Incorrect:

register CachedRepository() as Repository
      register ItemController() as Controller

Correct:

register InMemoryCache() as Cache
      register CachedRepository() as Repository
      register ItemController() as Controller

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

response <- controller.handle("/items/1").toUpperCase()

Correct:

response <- controller.handle("/items/1")
Other ways to ask this
  • Does EK9 catch missing component registrations?
  • What error do I get for unregistered dependencies in EK9?
  • How does EK9 handle missing DI bindings?

Coming from another language?

Java Spring: NoSuchBeanDefinitionException at runtime, UnsatisfiedDependencyException for @Autowired. Guice: ConfigurationException for missing bindings at Injector.getInstance(). .NET: InvalidOperationException 'No service for type'. Python: KeyError or AttributeError at runtime. Go: nil pointer at runtime. Rust: compile-time via generics, but no built-in DI. EK9: compile-time error identifies exact missing registration, zero runtime failures.

Keywords: registration, error, migrate, completeness, validate, compile, unsatisfied, forget, dependency, missing, inject, catch, binding