go-delve/delve · error
unreadable length: %v
Error message
unreadable length: %v
What it means
When loading a channel variable, Delve reads the 'qcount' field (structType.Field[1]) from the runtime hchan struct. If that memory load fails, the channel length cannot be determined and the whole channel variable is marked unreadable.
Source
Thrown at pkg/proc/variables.go:1695
return
}
sv := v.clone()
sv.RealType = godwarf.ResolveTypedef(&(chanType.TypedefType))
sv = sv.maybeDereference()
if sv.Unreadable != nil || sv.Addr == 0 {
return
}
v.Base = sv.Addr
structType, ok := sv.DwarfType.(*godwarf.StructType)
if !ok {
v.Unreadable = errors.New("bad channel type")
return
}
lenAddr, _ := sv.toField(structType.Field[1])
lenAddr.loadValue(loadSingleValue)
if lenAddr.Unreadable != nil {
v.Unreadable = fmt.Errorf("unreadable length: %v", lenAddr.Unreadable)
return
}
chanLen, _ := constant.Uint64Val(lenAddr.Value)
newStructType := &godwarf.StructType{}
*newStructType = *structType
newStructType.Field = make([]*godwarf.StructField, len(structType.Field))
for i := range structType.Field {
field := &godwarf.StructField{}
*field = *structType.Field[i]
if field.Name == "buf" {
field.Type = pointerTo(fakeArrayType(chanLen, chanType.ElemType), v.bi.Arch)
}
newStructType.Field[i] = field
}
v.RealType = &godwarf.ChanType{View on GitHub (pinned to a23773e6c3)
Solutions
- Print the channel variable itself rather than relying on its length; check chanBuf/base address validity first
- If using a core dump, verify the dump captured the heap region containing the channel (full-heap core, not filtered)
- Re-run the debug session; transient unreadable memory during a stopped process usually resolves on a fresh stop
- Check that the binary and core/debug info match (same build) so the hchan struct layout offsets are correct
Example fix
// before
print len(ch) // unreadable length: location registers not available
// after: inspect the channel struct first and confirm validity
print ch // shows unreadable flag if memory is bad
printf("%d\n", ch.qcount) // only if ch readable
Defensive patterns
Strategy: try-catch
Validate before calling
// Check the channel variable is readable before asking for len()
chVar, err := evalVariable("ch")
if err != nil || chVar.Unreadable != nil { /* fallback: print header manually */ } Try / catch
if v, err := dbg.EvalVariable(scope, "ch", cfg); err != nil {
// RPC-level failure
} else if v.Unreadable != nil {
log.Printf("channel unreadable: %v", v.Unreadable) // covers 'unreadable length'
} Prevention
- Use full (not filtered) core dumps when post-mortem debugging channels
- Keep binary and core/debug info from the same build
- Re-attach/re-stop the process if a transient read fails
When it happens
Trigger: Evaluating len(ch) or printing a channel variable where the hchan header memory is unreadable: the channel address is invalid, the buffer memory page is unmapped, or the target died mid-read.
Common situations: Inspecting channels in core dumps where the heap page containing the channel was not dumped; debugging a channel whose memory was freed/corrupted; evaluating a channel through a stale pointer after the program crashed.
Related errors
- unreadable tophash: %v
- Invalid type %s in slice array
- bad array base address %#x
- len must be less than or equal to %d
- short read
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/43f0682780db4ff2.
Report an issue: GitHub.