{"record":{"id":"43f0682780db4ff2","repo":"go-delve/delve","slug":"unreadable-length-v","errorCode":null,"errorMessage":"unreadable length: %v","messagePattern":"unreadable length: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/variables.go","lineNumber":1695,"sourceCode":"\t\treturn\n\t}\n\tsv := v.clone()\n\tsv.RealType = godwarf.ResolveTypedef(&(chanType.TypedefType))\n\tsv = sv.maybeDereference()\n\tif sv.Unreadable != nil || sv.Addr == 0 {\n\t\treturn\n\t}\n\tv.Base = sv.Addr\n\tstructType, ok := sv.DwarfType.(*godwarf.StructType)\n\tif !ok {\n\t\tv.Unreadable = errors.New(\"bad channel type\")\n\t\treturn\n\t}\n\n\tlenAddr, _ := sv.toField(structType.Field[1])\n\tlenAddr.loadValue(loadSingleValue)\n\tif lenAddr.Unreadable != nil {\n\t\tv.Unreadable = fmt.Errorf(\"unreadable length: %v\", lenAddr.Unreadable)\n\t\treturn\n\t}\n\tchanLen, _ := constant.Uint64Val(lenAddr.Value)\n\n\tnewStructType := &godwarf.StructType{}\n\t*newStructType = *structType\n\tnewStructType.Field = make([]*godwarf.StructField, len(structType.Field))\n\n\tfor i := range structType.Field {\n\t\tfield := &godwarf.StructField{}\n\t\t*field = *structType.Field[i]\n\t\tif field.Name == \"buf\" {\n\t\t\tfield.Type = pointerTo(fakeArrayType(chanLen, chanType.ElemType), v.bi.Arch)\n\t\t}\n\t\tnewStructType.Field[i] = field\n\t}\n\n\tv.RealType = &godwarf.ChanType{","sourceCodeStart":1677,"sourceCodeEnd":1713,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/variables.go#L1677-L1713","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nprint len(ch)            // unreadable length: location registers not available\n// after: inspect the channel struct first and confirm validity\nprint ch                 // shows unreadable flag if memory is bad\nprintf(\"%d\\n\", ch.qcount) // only if ch readable\n","handlingStrategy":"try-catch","validationCode":"// Check the channel variable is readable before asking for len()\nchVar, err := evalVariable(\"ch\")\nif err != nil || chVar.Unreadable != nil { /* fallback: print header manually */ }","typeGuard":null,"tryCatchPattern":"if v, err := dbg.EvalVariable(scope, \"ch\", cfg); err != nil {\n    // RPC-level failure\n} else if v.Unreadable != nil {\n    log.Printf(\"channel unreadable: %v\", v.Unreadable) // covers 'unreadable length'\n}","preventionTips":["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"],"tags":["delve","channel","memory","variables"],"backgroundTag":"unreadable-memory","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}