go-delve/delve · error

interface conversion: %s is nil, not %s

Error message

interface conversion: %s is nil, not %s

What it means

After loading an interface value for a type assertion '<iface>.(T)', Delve checks the dynamic value stored in the interface. If the interface is nil (the data child has Addr == 0, meaning no dynamic value), the assertion fails with 'interface conversion: <iface type> is nil, not <T>'.

Source

Thrown at pkg/proc/eval.go:2144

// Evaluates expressions <subexpr>.(<type>)
func (scope *EvalScope) evalTypeAssert(op *evalop.TypeAssert, stack *evalStack) {
	xv := stack.pop()
	if xv.Kind != reflect.Interface {
		stack.err = fmt.Errorf("expression %q not an interface", astutil.ExprToString(op.Node.X))
		return
	}
	xv.loadInterface(0, false, LoadFullValue())
	if xv.Unreadable != nil {
		stack.err = xv.Unreadable
		return
	}
	if xv.Children[0].Unreadable != nil {
		stack.err = xv.Children[0].Unreadable
		return
	}
	if xv.Children[0].Addr == 0 {
		stack.err = fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), astutil.ExprToString(op.Node.Type))
		return
	}
	typ := op.DwarfType
	if typ != nil && xv.Children[0].DwarfType.Common().Name != typ.Common().Name {
		stack.err = fmt.Errorf("interface conversion: %s is %s, not %s", xv.DwarfType.Common().Name, xv.Children[0].TypeString(), typ.Common().Name)
		return
	}
	// loadInterface will set OnlyAddr for the data member since here we are
	// passing false to loadData, however returning the variable with OnlyAddr
	// set here would be wrong since, once the expression evaluation
	// terminates, the value of this variable will be loaded.
	xv.Children[0].OnlyAddr = false
	stack.push(&xv.Children[0])
}

// Evaluates expressions <subexpr>[<subexpr>] (subscript access to arrays, slices and maps)
func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
	idxev := stack.pop()

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Check the interface for nil before asserting: write the condition as 'err != nil && err.(MyErr).Code == 1'.
  2. Verify assignment: ensure the interface variable was populated before the assertion point.
  3. Use a comma-ok style check in real code (v, ok := x.(T)); in the debugger just print x first to see it is nil.
  4. If inspecting a nil error, print it directly instead of asserting.

Example fix

// before (breakpoint condition, err is nil interface)
cond 1 err.(MyErr).Code == 1
// error: interface conversion: error is nil, not MyErr
// after
cond 1 err != nil && err.(MyErr).Code == 1
Defensive patterns

Strategy: validation

Validate before calling

// In any condition or expression, guard the nil interface first:
// err != nil && err.(MyErr).Code == 1
// CLI check: dlv> print err   // confirm non-nil before asserting

Try / catch

res, err := scope.EvalExpression(assertExpr, cfg)
if err != nil && strings.Contains(err.Error(), "interface conversion:") && strings.Contains(err.Error(), "is nil") {
    // interface was nil; skip or handle nil case
}

Prevention

When it happens

Trigger: Evaluating 'x.(T)' (print, call, breakpoint condition, watchpoint) where x is a nil interface — its type is known but it holds no dynamic value.

Common situations: Asserting on interface variables that were never assigned, function parameters of interface type that the caller passed as nil, or error variables that are nil at the point of inspection.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/827b8364e631a5c5. Report an issue: GitHub.