caddyserver/caddy · error

storing ECH config metadata: %v

Error message

storing ECH config metadata: %v

What it means

Final of three storage writes for a new ECH config: meta.json (creation timestamp) under ech/configs/<configID>/. A failure leaves the config ID half-populated (key.bin and config.bin present, meta.json missing). The config-creation routine returns the error, so ECH is not enabled for this start; the stranded files are ignored on later runs except that the ID is considered taken.

Source

Thrown at modules/caddytls/ech.go:688

	}
	metaBytes, err := json.Marshal(meta)
	if err != nil {
		return echConfig{}, fmt.Errorf("marshaling ECH config metadata: %v", err)
	}

	parentKey := path.Join(echConfigsKey, strconv.Itoa(int(configID)))
	keyKey := path.Join(parentKey, "key.bin")
	configKey := path.Join(parentKey, "config.bin")
	metaKey := path.Join(parentKey, "meta.json")

	if err := ctx.Storage().Store(ctx, keyKey, privKeyBytes); err != nil {
		return echConfig{}, fmt.Errorf("storing ECH private key: %v", err)
	}
	if err := ctx.Storage().Store(ctx, configKey, echConfigBytes); err != nil {
		return echConfig{}, fmt.Errorf("storing ECH config: %v", err)
	}
	if err := ctx.Storage().Store(ctx, metaKey, metaBytes); err != nil {
		return echConfig{}, fmt.Errorf("storing ECH config metadata: %v", err)
	}

	echCfg.privKeyBin = privKeyBytes
	echCfg.configBin = echConfigBytes // this contains the public key
	echCfg.meta = meta

	return echCfg, nil
}

// ECH represents an Encrypted ClientHello configuration.
//
// EXPERIMENTAL: Subject to change.
type ECHConfiguration struct {
	// The public server name (SNI) that will be used in the outer ClientHello.
	// This should be a domain name for which this server is authoritative,
	// because Caddy will try to provision a certificate for this name. As an
	// outer SNI, it is never used for application data (HTTPS, etc.), but it
	// is necessary for enabling clients to connect securely in some cases.

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Inspect the wrapped storage error (it names the real cause) and fix the backend.
  2. Restart Caddy to retry provisioning with a new config ID.
  3. Clean up partial ech/configs/<id> directories missing meta.json to reclaim IDs if the 256-ID space ever fills.
  4. Stabilize the storage layer (disk space, network, credentials) before re-enabling ECH.
Defensive patterns

Strategy: retry

Try / catch

if err != nil && strings.Contains(err.Error(), "storing ECH config metadata") {
    // final write failed; retry provisioning after storage repair
}

Prevention

When it happens

Trigger: ctx.Storage().Store for meta.json fails after two prior successful writes — transient storage errors, disk-full occurring mid-sequence, remote storage timeout.

Common situations: Same class as the other ECH store failures: intermittent remote storage, quota exhaustion between writes, container filesystem issues.

Related errors


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