go-delve/delve · error
interface conversion: %s is %s, not %s
Error message
interface conversion: %s is %s, not %s
What it means
The mismatched-type variant of interface conversion failure: for 'x.(T)', if the assertion target type T (op.DwarfType) is non-nil and the dynamic type stored in the interface differs by name, evaluation fails with 'interface conversion: <iface name> is <dynamic type>, not <T>'. It mirrors Go's runtime panic but is produced at expression-evaluation time.
Source
Thrown at pkg/proc/eval.go:2149
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()
xev := stack.pop()
if xev.Unreadable != nil {
stack.err = xev.Unreadable
return
}View on GitHub (pinned to a23773e6c3)
Solutions
- Print the interface first ('print x') to see the actual dynamic type, then assert that type.
- Unwrap errors before asserting: check err.(*fmt.wrapError).Unwrap() or use errors.As in the program.
- Use the correct concrete type in the assertion (pointer vs value matters: T vs *T).
- Replace the assertion in a condition with a safe check like 'x != nil' plus the right type.
Example fix
// before dlv> print err.(MyErr) // error: interface conversion: error is *fmt.wrapError, not main.MyErr // after dlv> print err.(*fmt.wrapError) // or assert the actual dynamic type seen in 'print err'
Defensive patterns
Strategy: validation
Validate before calling
// Print the interface to learn its dynamic type before asserting: // dlv> print x // then assert exactly the printed concrete type (including *T vs T).
Try / catch
res, err := scope.EvalExpression(assertExpr, cfg)
if err != nil && strings.Contains(err.Error(), "interface conversion:") && strings.Contains(err.Error(), ", not ") {
// dynamic type differs from asserted type; re-read err message for actual type
} Prevention
- print the interface to discover the true dynamic type first
- match pointer/value exactly (*MyErr vs MyErr)
- unwrap wrapped errors before asserting your type
- watch for type changes across library versions
When it happens
Trigger: Evaluating 'x.(T)' where the interface holds a concrete value of a different type than T — e.g. err.(MyErr) when err actually holds *errors.errorString or a different concrete type.
Common situations: Asserting the wrong concrete type when multiple types implement the same interface, asserting on error values that are wrapped (fmt.Errorf produces *fmt.wrapError, not MyErr), or version drift where the stored type changed.
Related errors
- expression %q not an interface
- interface conversion: %s is nil, not %s
- variable to reslice is not an array, slice, or map
- invalid interface type
- invalid argument 1 %s (type %s) to complex
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/844424532931fb85.
Report an issue: GitHub.