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
- Check the interface for nil before asserting: write the condition as 'err != nil && err.(MyErr).Code == 1'.
- Verify assignment: ensure the interface variable was populated before the assertion point.
- 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.
- 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
- always precede type assertions on interfaces with a nil check
- print the interface first to see whether it holds a value
- check that assignment happened before the assertion point
- mirror comma-ok style (v, ok := x.(T)) in conditions
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
- expression %q not an interface
- interface conversion: %s is %s, not %s
- invalid interface type
- mismatched types nil and %s
- can not convert value of type %s to %s: %v
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/827b8364e631a5c5.
Report an issue: GitHub.