go-delve/delve · error

expression %q not an interface

Error message

expression %q not an interface

What it means

evalTypeAssert implements '<expr>.(<type>)' casts. A type assertion is only meaningful on interface values, so when the popped operand's reflect.Kind is not Interface, evaluation fails with 'expression %q not an interface'.

Source

Thrown at pkg/proc/eval.go:2131

	// Prevent abuse, attempting to call "\"fake\".member" directly.
	if xv.Addr == 0 && xv.Name == "" && xv.DwarfType == nil && xv.RealType == nil {
		stack.err = fmt.Errorf("%s (type %s) is not a struct", xv.Value, xv.TypeString())
		return
	}
	// Special type conversions for CPU register variables (REGNAME.int8, etc)
	if xv.Flags&VariableCPURegister != 0 && !xv.loaded {
		stack.pushErr(xv.registerVariableTypeConv(op.Name))
		return
	}

	stack.pushErr(xv.findStructMemberOrMethod(op.Name, true))
}

// 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)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Remove the type assertion if the expression is already the concrete type and use it directly.
  2. If a conversion is intended, use Go conversion syntax T(x) instead of x.(T).
  3. Assert on the interface-typed expression instead, e.g. if the value is stored in an interface variable, write 'iface.(T)'.
  4. Use 'print <expr>' to inspect the static type (Kind) before writing the assertion.

Example fix

// before (x is declared as int)
dlv> print x.(int)
// error: expression "x" not an interface
// after
dlv> print x        // already an int
// or, if x is an interface:
dlv> print x.(int)
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm the operand is an interface before asserting:
// dlv> print x        // shows the static type; if it's concrete, skip the assertion

Type guard

// Only build x.(T) when x's static type is an interface:
if v := eval(xExpr); v.Kind == reflect.Interface {
    expr = fmt.Sprintf("%s.(%s)", xExpr, targetTypeName)
} else {
    expr = xExpr // already concrete, use directly
}

Try / catch

res, err := scope.EvalExpression(assertExpr, cfg)
if err != nil && strings.Contains(err.Error(), "not an interface") {
    // use the value directly or convert with T(x) instead of x.(T)
}

Prevention

When it happens

Trigger: Writing '<expr>.(T)' where <expr> evaluates to a concrete (non-interface) type — e.g. 'x.(int)' where x is already declared int — in a print/eval expression, breakpoint condition, or watchpoint.

Common situations: Copy-pasting runtime type assertions onto variables that the debugger already sees as concrete; confusing type assertions (x.(T)) with type conversions (T(x)); using assertions in bp conditions on concrete-typed locals.

Related errors


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