caddyserver/caddy · error

module name '%s': %v

Error message

module name '%s': %v

What it means

loadModuleMap handles fields typed caddy.ModuleMap (map[string]json.RawMessage) where the MAP KEY is the module name (namespace already implied by the field's caddy tag). It calls ctx.LoadModuleByID(namespace+"."+key, value) per entry; any failure is wrapped as "module name '%s': %v" naming the map key. The inner error is usually 'unknown module', a decode failure, or a provision/validate failure.

Source

Thrown at context.go:347

	}
	return mods, nil
}

// loadModuleMap loads modules from a ModuleMap, i.e. map[string]any, where the key is the
// module name. With a module map, module names do not need to be defined inline with their values.
func (ctx Context) loadModuleMap(namespace string, val reflect.Value) (map[string]any, error) {
	all := make(map[string]any)
	iter := val.MapRange()
	for iter.Next() {
		k := iter.Key().Interface().(string)
		v := iter.Value().Interface().(json.RawMessage)
		moduleName := namespace + "." + k
		if namespace == "" {
			moduleName = k
		}
		val, err := ctx.LoadModuleByID(moduleName, v)
		if err != nil {
			return nil, fmt.Errorf("module name '%s': %v", k, err)
		}
		all[k] = val
	}
	return all, nil
}

// LoadModuleByID decodes rawMsg into a new instance of mod and
// returns the value. If mod.New is nil, an error is returned.
// If the module implements Validator or Provisioner interfaces,
// those methods are invoked to ensure the module is fully
// configured and valid before being used.
//
// This is a lower-level method and will usually not be called
// directly by most modules. However, this method is useful when
// dynamically loading/unloading modules in their own context,
// like from embedded scripts, etc.
func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error) {
	modulesMu.RLock()

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Check the module name given in quotes against `caddy list-modules --packages` output for the expected namespace
  2. If the module comes from a plugin, rebuild with `xcaddy build --with <plugin@version>` or use a Caddy build that includes it
  3. Fix the JSON body of that entry if the inner error mentions decoding or provisioning
  4. Align config and binary versions: configs adapted by/for newer Caddy versions may reference renamed modules

Example fix

// before
"dns_challenge": { "cloudfare": {} } // typo in module name key
// after
"dns_challenge": { "cloudflare": { "api_token": "{env.CF_TOKEN}" } }
Defensive patterns

Strategy: validation

Validate before calling

// Verify each ModuleMap key resolves to a registered module before load
mods := caddy.GetModules("dns") // or the relevant namespace
for name := range moduleMap {
    if _, ok := mods[name]; !ok {
        return fmt.Errorf("module name '%s' not registered in namespace", name)
    }
}

Type guard

func moduleRegistered(id string) bool {
    for _, m := range caddy.Modules() { if m == id { return true } }
    return false
}

Try / catch

if _, err := ctx.LoadModule(field, raw); err != nil { return fmt.Errorf("%s: %w", field, err) } // 'module name K:' names the key

Prevention

When it happens

Trigger: A struct field of type caddy.ModuleMap tagged caddy:"module=namespace"; during LoadModule, an entry's key resolves to namespace.key which is not registered, or its JSON value fails StrictUnmarshalJSON/Provision/Validate, producing fmt.Errorf("module name '%s': %v", k, err).

Common situations: Using a DNS provider module (e.g. acme_dns) whose plugin is not compiled into the binary; misspelling the module name as the map key; a config written for a newer Caddy version using a module name that does not exist in the installed one.

Related errors


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