go-delve/delve · error
escape check for %s failed, variable unreadable: %v
Error message
escape check for %s failed, variable unreadable: %v
What it means
allPointers walks an actual argument variable to check pointer escape, but if the variable itself (or a child) is Unreadable — memory could not be read, or the value couldn't be loaded — the escape check cannot proceed and this error is returned, aborting the call injection.
Source
Thrown at pkg/proc/fncall.go:737
func funcCallArgRegABI(fn *Function, bi *BinaryInfo, entry reader.Variable, argname string, typ godwarf.Type, pargFrameSize *int64) (*funcCallArg, error) {
// Conservatively calculate the full stack argument space for ABI0.
*pargFrameSize = alignAddr(*pargFrameSize, typ.Align())
*pargFrameSize += typ.Size()
isret, _ := entry.Val(dwarf.AttrVarParam).(bool)
return &funcCallArg{name: argname, typ: typ, dwarfEntry: entry.Tree, isret: isret}, nil
}
// alignAddr rounds up addr to a multiple of align. Align must be a power of 2.
func alignAddr(addr, align int64) int64 {
return (addr + align - 1) &^ (align - 1)
}
// allPointers calls f on every pointer contained in v
func allPointers(v *Variable, name string, f func(addr uint64, name string) error) error {
if v.Unreadable != nil {
return fmt.Errorf("escape check for %s failed, variable unreadable: %v", name, v.Unreadable)
}
switch v.Kind {
case reflect.Ptr, reflect.UnsafePointer:
var w *Variable
if len(v.Children) == 1 {
// this branch is here to support pointers constructed with typecasts from ints or the '&' operator
w = &v.Children[0]
} else {
w = v.maybeDereference()
}
return f(w.Addr, name)
case reflect.Chan, reflect.String, reflect.Slice:
return f(v.Base, name)
case reflect.Map:
sv := v.clone()
sv.RealType = godwarf.ResolveTypedef(&(v.RealType.(*godwarf.MapType).TypedefType))
sv = sv.maybeDereference()
return f(sv.Addr, name)View on GitHub (pinned to a23773e6c3)
Solutions
- Print the argument first to confirm it is readable before calling
- Fix/refresh the pointer so it refers to valid live memory
- Disable the escape check if the value is provably safe but unreadable to the checker
Example fix
// before call Use(p) // p unreadable -> escape check fails // after print p // verify readable first call Use(*p)
Defensive patterns
Strategy: validation
Validate before calling
v, err := scope.EvalExpression(expr, loadCfg)
if err != nil || v.Unreadable != nil {
return errors.New("argument not readable; fix pointer/memory before call injection")
} Type guard
func readable(v *proc.Variable) bool { return v != nil && v.Unreadable == nil } Try / catch
if err != nil && strings.Contains(err.Error(), "variable unreadable") {
// inspect the argument first, or retry after the target advances to valid state
} Prevention
- print each pointer argument before injecting a call to confirm readability
- Avoid arguments built from stale or dangling pointers
When it happens
Trigger: Calling a function whose argument's memory is unreadable at check time: freed/unmapped memory, invalid pointer constructed by cast, register-based value not yet materialized, or unreadable children during the recursive walk.
Common situations: Arguments built from stale pointers, values living in registers of a stopped thread that can't be read, or corrupted heap during debugging of a crashing program.
Related errors
- cannot use %s as argument %s in function %s: stack object pa
- internal debugger error: eval program finished without error
- internal debugger error: could not undo injected call during
- unsupported pointer size %d
- expression %q is not a function
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/8b35e9ecdb9e37bc.
Report an issue: GitHub.