caddyserver/caddy · error

module name not specified with key '%s' in %+v

Error message

module name not specified with key '%s' in %+v

What it means

Inline module maps in Caddy JSON (e.g. a handler object {"handler": "..."}, or matchers {"match": ...}) are decoded by getModuleNameInline, which unmarshals the object to a map and extracts the module-name key. If that key is absent, not a string, or empty, this error is returned showing the whole object.

Source

Thrown at modules.go:272

	sort.Strings(names)

	return names
}

// getModuleNameInline loads the string value from raw of moduleNameKey,
// where raw must be a JSON encoding of a map. It returns that value,
// along with the result of removing that key from raw.
func getModuleNameInline(moduleNameKey string, raw json.RawMessage) (string, json.RawMessage, error) {
	var tmp map[string]any
	err := json.Unmarshal(raw, &tmp)
	if err != nil {
		return "", nil, err
	}

	moduleName, ok := tmp[moduleNameKey].(string)
	if !ok || moduleName == "" {
		return "", nil, fmt.Errorf("module name not specified with key '%s' in %+v", moduleNameKey, tmp)
	}

	// remove key from the object, otherwise decoding it later
	// will yield an error because the struct won't recognize it
	// (this is only needed because we strictly enforce that
	// all keys are recognized when loading modules)
	delete(tmp, moduleNameKey)
	result, err := json.Marshal(tmp)
	if err != nil {
		return "", nil, fmt.Errorf("re-encoding module configuration: %v", err)
	}

	return moduleName, result, nil
}

// Provisioner is implemented by modules which may need to perform
// some additional "setup" steps immediately after being loaded.
// Provisioning should be fast (imperceptible running time). If

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Find the object printed in the error (%+v shows its keys) and add the missing name key — commonly "handler" inside route objects, "match" inside matchers, "wrapper" inside listener wrappers.
  2. Ensure the key's value is a non-empty JSON string.
  3. Prefer generating JSON with 'caddy adapt' from a Caddyfile so keys are always well-formed.
  4. Validate configs with 'caddy validate --config x.json --adapter json' before loading.

Example fix

// before (json)
{"route": [{"handle": [{"statuses": 404}]}]}

// after
{"route": [{"handle": [{"handler": "error", "status_code": 404}]}]}
Defensive patterns

Strategy: validation

Validate before calling

// client-side check that every inline module object has its name key
func hasModuleKey(obj map[string]any, key string) error {
    name, ok := obj[key].(string)
    if !ok || name == "" {
        return fmt.Errorf("object %v missing module name key %q", obj, key)
    }
    return nil
}

Try / catch

if err := json.Unmarshal(cfgJSON, &cfg); err != nil {
    if strings.Contains(err.Error(), "module name not specified") {
        // the error prints the offending object — add the missing key (handler/match/wrapper)
    }
    return err
}

Prevention

When it happens

Trigger: A JSON config where an inline module object omits its discriminator key: a route handler without "handler", a listener wrapper without "wrapper", a matcher without "match" — or where the key's value is a number/null/empty string.

Common situations: Hand-written or templated JSON configs; JSON produced by converting Caddyfile output and then hand-stripping keys; API clients (caddy adapt/load over the admin endpoint) sending partially-built objects; version drift after a key rename.

Related errors


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