uber-go/zap · error

may not contain

Error message

may not contain %q

What it means

normalizeScheme validates a URL scheme used when registering a custom sink via RegisterSink. A scheme may only contain ASCII letters, digits, '.', '+', and '-'. If any other character is found, the sink is rejected with this error naming the offending character.

Solutions

  1. Remove or replace the illegal character in the scheme passed to RegisterSink (use letters, digits, '.', '+', '-' only).
  2. Use '_' alternatives such as '-' for multi-word schemes, e.g. "my-sink" instead of "my_sink".
  3. Validate/normalize the scheme string (strings.TrimSpace, regexp ^[A-Za-z0-9.+-]+$) before calling RegisterSink.

Example fix

// before
err := zap.RegisterSink("my_sink", factory)
// after
err := zap.RegisterSink("my-sink", factory)
Defensive patterns

Strategy: validation

Validate before calling

var schemeRe = regexp.MustCompile(`^[A-Za-z0-9.+-]+$`)
if !schemeRe.MatchString(scheme) {
    return fmt.Errorf("invalid sink scheme %q", scheme)
}
err := zap.RegisterSink(scheme, factory)

Prevention

When it happens

Trigger: Calling zap.RegisterSink with a scheme containing illegal characters, e.g. RegisterSink("my sink", factory) or RegisterSink("s3+bucket!", ...) — any scheme character outside [A-Za-z0-9.+-] triggers it.

Common situations: Typos or spaces in scheme names, copy-pasted scheme strings with uppercase-delimiting characters like '_' (which is NOT allowed), dynamically built scheme names from user input or config values.

Related errors


AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31). Data as JSON: /api/errors/070113ecd0dea072. Report an issue: GitHub.

Appendix: source

Thrown at sink.go:177

}

func normalizeScheme(s string) (string, error) {
	// https://tools.ietf.org/html/rfc3986#section-3.1
	s = strings.ToLower(s)
	if first := s[0]; 'a' > first || 'z' < first {
		return "", errors.New("must start with a letter")
	}
	for i := 1; i < len(s); i++ { // iterate over bytes, not runes
		c := s[i]
		switch {
		case 'a' <= c && c <= 'z':
			continue
		case '0' <= c && c <= '9':
			continue
		case c == '.' || c == '+' || c == '-':
			continue
		}
		return "", fmt.Errorf("may not contain %q", c)
	}
	return s, nil
}

View on GitHub (pinned to bbd4ecbd87)