caddyserver/caddy · error

loading storage module: %v

Error message

loading storage module: %v

What it means

Returned by CA.Provision when ctx.LoadModule(ca, "StorageRaw") fails to load the CA's custom storage module from its raw JSON. LoadModule resolves the module name in the storage namespace and instantiates it; failure means an unknown module name, a module not compiled into the binary, or malformed module JSON. The %v wraps caddy's module-loading error, which names the offending module.

Source

Thrown at modules/caddypki/ca.go:114

}

// Provision sets up the CA.
func (ca *CA) Provision(ctx caddy.Context, id string, log *zap.Logger) error {
	ca.mu = new(sync.RWMutex)
	ca.log = log.Named("ca." + id)
	ca.ctx = ctx

	if id == "" {
		return fmt.Errorf("CA ID is required (use 'local' for the default CA)")
	}
	ca.mu.Lock()
	ca.ID = id
	ca.mu.Unlock()

	if ca.StorageRaw != nil {
		val, err := ctx.LoadModule(ca, "StorageRaw")
		if err != nil {
			return fmt.Errorf("loading storage module: %v", err)
		}
		cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()
		if err != nil {
			return fmt.Errorf("creating storage configuration: %v", err)
		}
		ca.storage = cmStorage
	}
	if ca.storage == nil {
		ca.storage = ctx.Storage()
	}

	if ca.Name == "" {
		ca.Name = defaultCAName
	}
	if ca.RootCommonName == "" {
		ca.RootCommonName = defaultRootCommonName
	}
	if ca.IntermediateCommonName == "" {

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Check the wrapped error — it says which module failed to load
  2. Build Caddy with the plugin: xcaddy build --with github.com/.../caddy-storage-redis, or use a build that includes it
  3. Fix the module name under storage.module to match the plugin's registered caddy.ModuleInfo ID
  4. Or drop the per-CA storage block to fall back to the global/default storage

Example fix

# before (stock binary)
caddy run --config Caddyfile   # storage.module: redis → error

# after
xcaddy build --with github.com/graywindy/caddy-storage-redis
./caddy run --config Caddyfile
Defensive patterns

Strategy: validation

Validate before calling

// Verify the storage plugin is compiled in before loading config:
cmd := exec.Command(caddyBin, "list-modules")
out, _ := cmd.Output()
if !bytes.Contains(out, []byte("caddy.storage."+moduleName)) {
    return fmt.Errorf("storage module %q not in build; rebuild with xcaddy --with", moduleName)
}

Type guard

// After loading, assert the module implements StorageConverter:
if _, ok := loaded.(caddy.StorageConverter); !ok {
    return errors.New("module is not a storage converter")
}

Try / catch

// Catch the wrap and point at the build, not the config:
if err := ca.Provision(ctx, id, log); err != nil {
    if strings.Contains(err.Error(), "loading storage module") {
        return fmt.Errorf("storage plugin missing from build: %v", err)
    }
}

Prevention

When it happens

Trigger: Configuring a CA with "storage": {"module": "redis", ...} when the caddy.storage.redis plugin is not built into the custom Caddy binary; a typo in the module key; JSON for the storage module that fails its own unmarshaling. LoadModule returns the error and it is re-wrapped here.

Common situations: Switching from a plugin build (xcaddy) to the stock caddy binary and keeping custom storage config; plugin removed during a build-script cleanup; storage module renamed between plugin versions; env-specific configs where only some builds include the plugin.

Related errors


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