go-delve/delve · error
%s (type %s) is not a struct
Error message
%s (type %s) is not a struct
What it means
This error is raised by evalStructSelector when a field-access expression like <expr>.<field> is attempted on a value that is not a struct. Specifically it guards against the literal expression 'nil.member': when the popped variable has a zero address and Name "nil", Delve refuses the selector with this message.
Source
Thrown at pkg/proc/eval.go:2110
}
if v {
best = args[i]
}
}
if best == nil {
return nil, fmt.Errorf("not enough arguments to %s", name)
}
return best, nil
}
// Evaluates expressions <subexpr>.<field name> where subexpr is not a package name
func (scope *EvalScope) evalStructSelector(op *evalop.Select, stack *evalStack) {
xv := stack.pop()
// Prevent abuse, attempting to call "nil.member" directly.
if xv.Addr == 0 && xv.Name == "nil" {
stack.err = fmt.Errorf("%s (type %s) is not a struct", xv.Name, xv.TypeString())
return
}
// 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) {View on GitHub (pinned to a23773e6c3)
Solutions
- Replace 'nil.<field>' with the intended variable or expression that holds the struct.
- If testing for nil, compare instead: write '<expr> == nil' rather than selecting fields from nil.
- Guard pointer dereferences in conditions: '<ptr> != nil && <ptr>.Field ...'.
- Check the expression for typos where a real struct variable name was meant.
Example fix
// before (breakpoint condition) cond 1 nil.next != nil // error: nil (type nil) is not a struct // after cond 1 p != nil && p.next != nil
Defensive patterns
Strategy: type-guard
Validate before calling
// In a breakpoint condition, guard nil receivers: // p != nil && p.Field ... // In expression: never write 'nil.<field>'.
Type guard
// CLI-side guard before building a selector expression:
if expr == "nil" || strings.HasPrefix(expr, "nil.") {
return errors.New("selector on nil literal is invalid")
} Try / catch
res, err := scope.EvalExpression(selExpr, cfg)
if err != nil && strings.Contains(err.Error(), "is not a struct") {
// expression selected a field on nil; rewrite the expression
} Prevention
- never apply '.' to the literal nil
- guard pointer dereferences in conditions with 'x != nil &&'
- check for typos where a variable name was replaced by nil
- use '== nil' comparisons to test for nil instead of field access
When it happens
Trigger: Evaluating an expression such as 'nil.Foo' or 'nil.Field' at the debugger prompt (or in a breakpoint condition/watchpoint compiled through EvalExpression) where the receiver of '.' is the literal nil.
Common situations: Typing 'nil.member' accidentally instead of a variable name, or writing a breakpoint condition that dereferences nil, e.g. cond on a bp written as 'nil.next != nil'.
Related errors
- could not decode first frame
- unable to find function context
- unable to find locals: no debug information present in binar
- no address for escaped variable
- can not assign to function expression
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/12f60d248954a0ef.
Report an issue: GitHub.