EpicGames/lore · critical

Failed to create hooks from configuration

Error message

Failed to create hooks from configuration

What it means

A `.expect("Failed to create hooks from configuration")` panic in the server startup path (`async_main`, invoked from `server_main`) when `hook_registry.create_enabled_hooks(&settings.hooks)` returns Err. This converts an invalid hooks configuration into a hard startup failure: the server refuses to boot rather than run with broken hooks.

Solutions

  1. Read the Err returned by create_enabled_hooks (replace expect temporarily or check logs) to see which hook name failed
  2. Fix the `hooks` section of the server settings file — correct hook names and required fields
  3. Confirm the hook's registration callback is registered so a factory exists for every enabled hook
  4. After upgrading, migrate the hooks config to the current schema
  5. Disable the offending hook to boot the server, then fix its configuration

Example fix

// before
let enabled_hooks = hook_registry
    .create_enabled_hooks(&settings.hooks)
    .expect("Failed to create hooks from configuration");
// after
let enabled_hooks = hook_registry.create_enabled_hooks(&settings.hooks)
    .unwrap_or_else(|e| {
        eprintln!("invalid hooks configuration: {e:?}");
        std::process::exit(1);
    });
Defensive patterns

Strategy: validation

Validate before calling

// Validate hooks config before startup
for (name, hook_cfg) in &settings.hooks {
    if !hook_registry.has_factory(name) {
        return Err(format!("unknown hook '{name}' in configuration"));
    }
    hook_registry.validate_hook_config(name, hook_cfg)?;
}

Try / catch

let enabled_hooks = hook_registry.create_enabled_hooks(&settings.hooks)
    .map_err(|e| format!("hook configuration error: {e}"))?;

Prevention

When it happens

Trigger: `settings.hooks` names a hook type that has no registered factory (registration callbacks didn't register it), or a hook's configuration section fails that hook's own config validation (missing/invalid fields, bad types, bad URLs/paths).

Common situations: Typo'd or renamed hook entries in the server config file after a version upgrade; enabling a built-in hook that was removed or moved behind a feature flag; hook config schema changed between versions so old settings no longer validate; a custom hook's registration callback not running before this call.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/5ae044d221016dbc. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/server.rs:1903

            &settings.notification,
            local_store().as_ref(),
            &settings.plugins,
        )
        .await?;

        // Build hook dispatcher: register build.rs-discovered hooks then config-provided hooks
        let hook_ctx = HookRegistrationContext {
            notification_sender: notification.clone(),
        };
        let mut hook_registry = HookRegistry::new();
        crate::hooks::register_all_hooks(&mut hook_registry, &hook_ctx);
        for callback in config.hook_registration_callbacks {
            callback(&mut hook_registry, &hook_ctx);
        }

        let enabled_hooks = hook_registry
            .create_enabled_hooks(&settings.hooks)
            .expect("Failed to create hooks from configuration");

        let hook_dispatcher = Arc::new(HookDispatcher::from_hooks_default(enabled_hooks));

        lore_spawn!(endpoints, {
            let immutable_store = immutable_store.clone();
            let mutable_store = mutable_store.clone();
            let lock_store = lock_store.clone();
            let jwt_verifier = jwt_verifier.clone();
            let repository_authorizer = repository_authorizer.clone();
            let settings = settings.clone();
            let notification = notification.clone();
            let user_agent_filter = user_agent_filter.clone();
            let forwarded_requests = forwarded_requests.clone();
            let shutdown_rx = _shutdown_rx.clone();

            let local_immutable_store = local_store().unwrap_or_else(|| {
                warn!("No local store available for gRPC server, operations requiring local store will route to the main store");
                immutable_store.clone()

View on GitHub (pinned to 074eb0b0d1)