uber-go/zap · error

missing EncodeTime in EncoderConfig

Error message

missing EncodeTime in EncoderConfig

What it means

newEncoder (used by zap.New production helpers and Config.buildEncoder) rejects an EncoderConfig whose TimeKey is set but whose EncodeTime function is nil, since zap cannot format timestamps without an EncodeTime. The check only applies when TimeKey is non-empty (i.e. time entries are emitted).

Source

Thrown at encoder.go:66

//
// Attempting to register an encoder whose name is already taken returns an
// error.
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error {
	_encoderMutex.Lock()
	defer _encoderMutex.Unlock()
	if name == "" {
		return errNoEncoderNameSpecified
	}
	if _, ok := _encoderNameToConstructor[name]; ok {
		return fmt.Errorf("encoder already registered for name %q", name)
	}
	_encoderNameToConstructor[name] = constructor
	return nil
}

func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
	if encoderConfig.TimeKey != "" && encoderConfig.EncodeTime == nil {
		return nil, errors.New("missing EncodeTime in EncoderConfig")
	}

	_encoderMutex.RLock()
	defer _encoderMutex.RUnlock()
	if name == "" {
		return nil, errNoEncoderNameSpecified
	}
	constructor, ok := _encoderNameToConstructor[name]
	if !ok {
		return nil, fmt.Errorf("no encoder registered for name %q", name)
	}
	return constructor(encoderConfig)
}

View on GitHub (pinned to bbd4ecbd87)

Solutions

  1. Set EncodeTime in the EncoderConfig, e.g. zapcore.EpochTimeEncoder, ISO8601TimeEncoder, or RFC3339TimeEncoder
  2. If you don't want timestamps, clear TimeKey to "" so the check is skipped

Example fix

// before
cfg := zapcore.EncoderConfig{TimeKey: "ts", MessageKey: "msg"}
// after
cfg := zapcore.EncoderConfig{TimeKey: "ts", MessageKey: "msg", EncodeTime: zapcore.ISO8601TimeEncoder}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.TimeKey != "" && cfg.EncodeTime == nil {
    cfg.EncodeTime = zapcore.ISO8601TimeEncoder
}
enc := zapcore.NewJSONEncoder(cfg)

Type guard

func hasEncodeTime(c zapcore.EncoderConfig) bool {
    return c.TimeKey == "" || c.EncodeTime != nil
}

Prevention

When it happens

Trigger: Constructing a zapcore.EncoderConfig manually with TimeKey set (e.g. "ts") but leaving EncodeTime nil, then calling zap.New(...) with that config or an encoder built from it.

Common situations: Copying an EncoderConfig snippet from docs but omitting EncodeTime; building encoder configs from structured/JSON config files where function fields cannot be deserialized and default to nil.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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