caddyserver/caddy · error

provision

Error message

provision %s: %v

What it means

LoadModuleByID calls Provision(ctx) on modules implementing the Provisioner interface so they can set themselves up (resolve dependencies, allocate clients). Any error returned is wrapped as 'provision %s: %v' with the ModuleInfo string identifying the module. The inner error text is the module's own and is the actual diagnosis.

Solutions

  1. Identify the module from the ModuleInfo text in the error and read the inner error message — it states what provisioning could not do
  2. Correct the module's config per its documented requirements (required fields, allowed values)
  3. Check environmental prerequisites: storage permissions, reachable endpoints, env vars referenced with {env.*} placeholders
  4. Search the module's source for the returned error string to understand the exact condition

Example fix

// before
{ "handler": "reverse_proxy", "upstream": "localhost:8080" } // wrong field
// after
{ "handler": "reverse_proxy", "upstreams": [ { "dial": "localhost:8080" } ] }
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := ctx.LoadModuleByID(id, raw); err != nil {
    var msg string
    if unwrapped := errors.Unwrap(err); unwrapped != nil { msg = unwrapped.Error() } else { msg = err.Error() }
    return fmt.Errorf("module %s provisioning failed: %s", id, msg)
}

Prevention

When it happens

Trigger: A module's Provision returns an error — invalid option combinations, missing required config, failed dependency lookup via ctx.App/ctx.LoadModule, environment problems (unreachable endpoint, bad credentials referenced at provision time).

Common situations: TLS/ACME modules failing on bad issuer config; plugins requiring non-nil fields that JSON left empty; Provision calling ctx.App for an app that itself failed to provision; permission errors opening storage paths.

Related errors


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

Appendix: source

Thrown at context.go:436

				ctx.cfg.failedApps[id] = err
			}
		}()
	}

	ctx.ancestry = append(ctx.ancestry, val)

	if prov, ok := val.(Provisioner); ok {
		err = prov.Provision(ctx)
		if err != nil {
			// incomplete provisioning could have left state
			// dangling, so make sure it gets cleaned 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("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)

View on GitHub (pinned to 50e54ee279)