caddyserver/caddy · error

%s is %w

Error message

%s is %w

What it means

The PROXY protocol module's Policy type fails to parse the configured policy name. parsePolicy uppercases the input and looks it up in policyMapRev, which only knows USE, IGNORE, REJECT, REQUIRE, and SKIP. Any other string is wrapped with errInvalidPolicy via '%s is %w'. The lookup is case-insensitive, so 'use' works but 'enable' does not.

Source

Thrown at modules/caddyhttp/proxyprotocol/policy.go:79

	return []byte(policyMap[x]), nil
}

// UnmarshalText implements the text unmarshaller method.
func (x *Policy) UnmarshalText(text []byte) error {
	name := string(text)
	tmp, err := parsePolicy(name)
	if err != nil {
		return err
	}
	*x = tmp
	return nil
}

func parsePolicy(name string) (Policy, error) {
	if x, ok := policyMapRev[strings.ToUpper(name)]; ok {
		return x, nil
	}
	return Policy(0), fmt.Errorf("%s is %w", name, errInvalidPolicy)
}

var errInvalidPolicy = errors.New("invalid policy")

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Set the policy to one of the five valid names: USE, IGNORE, REJECT, REQUIRE, or SKIP (any letter case).
  2. Remove surrounding quotes/whitespace and re-run 'caddy validate --config <file>' to confirm the value parses.
  3. If migrating from HAProxy-style configs, map ACCEPT->USE, IGNORE->IGNORE, REQUIRE->REJECT/REQUIRE depending on intent.

Example fix

# before (Caddyfile)
{
  servers {
    listener_wrappers {
      proxy_protocol allow
    }
  }
}

# after
{
  servers {
    listener_wrappers {
      proxy_protocol USE
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// before unmarshalling config text
var validPolicies = map[string]bool{"USE": true, "IGNORE": true, "REJECT": true, "REQUIRE": true, "SKIP": true}

func validPolicy(s string) bool { return validPolicies[strings.ToUpper(strings.TrimSpace(s))] }

if !validPolicy(cfg.Policy) {
    return fmt.Errorf("policy must be one of USE, IGNORE, REJECT, REQUIRE, SKIP; got %q", cfg.Policy)
}

Type guard

func isValidPolicy(name string) bool {
	_, ok := map[string]struct{}{"USE": {}, "IGNORE": {}, "REJECT": {}, "REQUIRE": {}, "SKIP": {}}[strings.ToUpper(strings.TrimSpace(name))]
	return ok
}

Prevention

When it happens

Trigger: Setting the 'policy' subdirective of the 'proxy_protocol' global option (Caddyfile) or the corresponding JSON field to a string outside {USE, IGNORE, REJECT, REQUIRE, SKIP} (case-insensitive). Also calling Policy.UnmarshalText directly (e.g. json.Unmarshal into a proxyprotocol.Policy) with an unrecognized value.

Common situations: Typos like 'reject ' with trailing whitespace (the value is not trimmed), 'ALLOW' or 'DENY' carried over from other PROXY-protocol implementations (HAProxy uses ACCEPT/IGNORE/REQUIRE), or a bare number where a name is expected.

Related errors


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