caddyserver/caddy · error

%s: invalid configuration: %v

Error message

%s: invalid configuration: %v

What it means

After a module is provisioned, LoadModuleByID calls Validate() on Validator implementations to check semantic correctness. Any error is wrapped as '%s: invalid configuration: %v' where %s identifies the module (its caddy.ModuleInfo string). This is the standard error users see when config is syntactically valid JSON but semantically wrong for the module.

Source

Thrown at context.go:450

				if err2 != nil {
					err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
				}
			}
			return nil, fmt.Errorf("provision %s: %v", modInfo, err)
		}
	}

	if validator, ok := val.(Validator); ok {
		err = validator.Validate()
		if err != nil {
			// since the module was already provisioned, make sure we clean up
			if cleanerUpper, ok := val.(CleanerUpper); ok {
				err2 := cleanerUpper.Cleanup()
				if err2 != nil {
					err = fmt.Errorf("%v; additionally, cleanup: %v", err, err2)
				}
			}
			return nil, fmt.Errorf("%s: invalid configuration: %v", modInfo, err)
		}
	}

	ctx.moduleInstances[id] = append(ctx.moduleInstances[id], val)

	// if the loaded module happens to be an app that can emit events, store it so the
	// core can have access to emit events without an import cycle
	if ee, ok := val.(eventEmitter); ok {
		if _, ok := ee.(App); ok {
			ctx.cfg.eventEmitter = ee
		}
	}

	return val, nil
}

// loadModuleInline loads a module from a JSON raw message which decodes to
// a map[string]any, where one of the object keys is moduleNameKey

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Read the inner error after 'invalid configuration:' — module validators are written to be descriptive
  2. Adjust the named module's options to satisfy the stated constraint
  3. If upgrading Caddy revealed this, check the changelog/release notes for the module's new validation rules and migrate the config
  4. Run `caddy validate --config <file> [--adapter <adapter>]` in CI to catch these before deploy

Example fix

// before
{ "handler": "reverse_proxy", "upstreams": [] }
// after
{ "handler": "reverse_proxy", "upstreams": [ { "dial": "127.0.0.1:8080" } ] }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the full config before running — surfaces module Validate() failures cleanly
if err := caddy.ValidateWithAdapter(cfgJSON, caddyfile.Adapter{}); err != nil { // or use CLI
    return err
}

Try / catch

if _, err := ctx.LoadModuleByID(id, raw); err != nil {
    if strings.Contains(err.Error(), "invalid configuration") {
        // semantic config error: fix options, not code
    }
    return err
}

Prevention

When it happens

Trigger: A module's Validate() returns an error: contradictory options, empty required collections, out-of-range values, invalid combinations that cannot be expressed as struct tags — e.g. an upstream with no dial addresses, a TLS policy with conflicting client auth settings.

Common situations: Reverse proxy blocks with zero upstreams; matchers with empty patterns; ACME configs combining incompatible options; version changes tightening validation rules so previously-accepted configs now fail after upgrade.

Related errors


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