uber-go/zap · error

can't unmarshal a nil *Level

Error message

can't unmarshal a nil *Level

What it means

zapcore.Level.UnmarshalText on a nil *Level cannot store the parsed result anywhere, so it returns the sentinel errUnmarshalNilLevel. This guard exists because the pointer receiver would otherwise dereference nil.

Source

Thrown at zapcore/level.go:29

// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zapcore

import (
	"bytes"
	"errors"
	"fmt"
)

var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level")

// A Level is a logging priority. Higher levels are more important.
type Level int8

const (
	// DebugLevel logs are typically voluminous, and are usually disabled in
	// production.
	DebugLevel Level = iota - 1
	// InfoLevel is the default logging priority.
	InfoLevel
	// WarnLevel logs are more important than Info, but don't need individual
	// human review.
	WarnLevel
	// ErrorLevel logs are high-priority. If an application is running smoothly,
	// it shouldn't generate any error-level logs.
	ErrorLevel
	// DPanicLevel logs are particularly important errors. In development the
	// logger panics after writing the message.

View on GitHub (pinned to bbd4ecbd87)

Solutions

  1. Declare a value zapcore.Level and call l.UnmarshalText(...) on its address: (&l).UnmarshalText(...)
  2. Ensure the enclosing struct's *Level field is non-nil before calling its Unmarshal methods

Example fix

// before
var l *zapcore.Level
l.UnmarshalText([]byte("info"))
// after
var l zapcore.Level
err := l.UnmarshalText([]byte("info"))
Defensive patterns

Strategy: type-guard

Validate before calling

var lvl zapcore.Level
if err := lvl.UnmarshalText([]byte(s)); err != nil {
    return err
}

Type guard

func unmarshalLevel(s string) (zapcore.Level, error) {
    var l zapcore.Level
    if err := l.UnmarshalText([]byte(s)); err != nil {
        return 0, err
    }
    return l, nil
}

Try / catch

var l zapcore.Level
if err := l.UnmarshalText(data); err != nil {
    return fmt.Errorf("parse level: %w", err)
}

Prevention

When it happens

Trigger: var l *zapcore.Level; l.UnmarshalText([]byte("info")) — calling UnmarshalText (or UnmarshalJSON, which routes through it) through a nil pointer.

Common situations: Unmarshaling config structs where the Level field pointer is nil and code calls its method directly; reflection-based decoders invoking methods on nil pointer fields.

Related errors


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