caddyserver/caddy · error

loading config loader module: %s

Error message

loading config loader module: %s

What it means

Thrown when the Admin.Config.LoadRaw module cannot be loaded via ctx.LoadModule. The dynamic config loader module (anything implementing ConfigLoader registered under the config load namespace) failed to provision or its raw JSON could not be decoded into the module.

Source

Thrown at caddy.go:614

	// so that cert management of this endpoint doesn't prevent user's
	// servers from starting which likely also use HTTP/HTTPS ports;
	// but before remote management which may depend on these creds)
	err := manageIdentity(ctx, cfg)
	if err != nil {
		return fmt.Errorf("provisioning remote admin endpoint: %v", err)
	}

	// replace any remote admin endpoint
	err = replaceRemoteAdminServer(ctx, cfg)
	if err != nil {
		return fmt.Errorf("provisioning remote admin endpoint: %v", err)
	}

	// if dynamic config is requested, set that up and run it
	if cfg != nil && cfg.Admin != nil && cfg.Admin.Config != nil && cfg.Admin.Config.LoadRaw != nil {
		val, err := ctx.LoadModule(cfg.Admin.Config, "LoadRaw")
		if err != nil {
			return fmt.Errorf("loading config loader module: %s", err)
		}

		logger := Log().Named("config_loader").With(
			zap.String("module", val.(Module).CaddyModule().ID.Name()),
			zap.Int("load_delay", int(cfg.Admin.Config.LoadDelay)))

		runLoadedConfig := func(config []byte) error {
			logger.Info("applying dynamically-loaded config")
			err := changeConfig(http.MethodPost, "/"+rawConfigKey, config, "", false)
			if errors.Is(err, errSameConfig) {
				return err
			}
			if err != nil {
				logger.Error("failed to run dynamically-loaded config", zap.Error(err))
				return err
			}
			logger.Info("successfully applied dynamically-loaded config")
			return nil

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Check the wrapped error: 'unknown module' means the loader is missing from the build; rebuild with the correct plugin
  2. Validate the admin.config.load JSON object against the loader module's expected schema
  3. If a custom loader, test its Provision() independently (e.g. via caddy adapt + unit tests)
  4. Remove admin.config temporarily to isolate whether the rest of the config is valid

Example fix

// before (module not in build)
{"admin": {"config": {"load": {"myloader": {}}}}}
// after (use a loader compiled in, e.g. http)
{"admin": {"config": {"load": {"http": {"url": "http://cfg.internal/current"}}}}}
Defensive patterns

Strategy: validation

Validate before calling

// confirm the loader module exists in this build before running
name := "http" // module name under config loaders
if _, found := caddy.GetModule("caddy.config_loaders." + name); ! found {
    return fmt.Errorf("loader %q not compiled in", name)
}

Prevention

When it happens

Trigger: cfg.Admin.Config.LoadRaw is non-nil (dynamic config requested) and ctx.LoadModule(cfg.Admin.Config, "LoadRaw") returns an error: unknown module name, invalid inline JSON for the loader, or the loader's Provision() failing.

Common situations: A config JSON with admin.config.load referencing a module that is not compiled into the custom Caddy build, or with malformed loader arguments. Also occurs when a third-party loader module panics/errors during provisioning.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/9e9e47fedc31db27. Report an issue: GitHub.