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

  1. Print the channel variable itself rather than relying on its length; check chanBuf/base address validity first
  2. If using a core dump, verify the dump captured the heap region containing the channel (full-heap core, not filtered)
  3. Re-run the debug session; transient unreadable memory during a stopped process usually resolves on a fresh stop
  4. 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

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


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