Go version

go version go1.25.0 darwin/arm64

Output of go env in your module/workspace:

AR='ar'
CC='cc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='c++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHEPROG=''
GODEBUG=''
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/7l/x6164vd11g73syllmzrm8nkc0000gp/T/go-build3087497557=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOOS='darwin'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.25.0/libexec'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.25.0/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.25.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

package main

import (
    "fmt"
    "io"
    "net/http"
)

type (
    A struct {
    }

    ArgsA struct {
        URL string
    }
)

func (a *A) MethodA(args *ArgsA) (string, error) {
    resp, err := http.Get(args.URL)
    if err != nil {
        return "", nil
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return "", nil
    }

    return string(body), nil
}

type (
    B struct {
        a *A
    }

    ArgsB struct {
        URL string
    }
)

func (b *B) MethodB(args *ArgsB) error {
    r, err := b.a.MethodA(&ArgsA{
        URL: args.URL,
    })
    if err != nil {
        return err
    }
    fmt.Println(r)

    return nil
}

func main() {
    b := &B{
        a: &A{},
    }
    if err := b.MethodB(&ArgsB{
        URL: "https://jsonplaceholder.typicode.com/posts",
    }); err != nil {
        panic(err)
    }
}

There is a reproducer and a binary.

What did you see happen?

I launched debug session via default Run and Debug button at VS Code without launch.json

before MethodA invocation, got expected value of args.URL: Image

after MethodA invocation, got unpredictable value. It can be "unreadable could not read string at 0x4 due to protocol error E08 during memory read for packet $m4", empty string or something like at screenshot below: Image

If don't call http.Get and just return string synchronously or use the variable args after http.Get there won't be a problem, otherwise: Image

Image

What did you expect to see?

I expect to see via debugger the same value of args before and after method (where it was used) called.

PS It seems the problem happened when I updated golang to the latest version, previously it was 1.24.4 as I remember. Also I tried the same example at Windows laptop and it works fine. I already reported an issue at delve project. They said it probably has to do with compiler optimizations not debugger @aarzilli

Full Environment:

Delve Debugger Version: 1.25.1 Build: $Id: 4e95e55b6b38b12e8509c91ec55261df1f7ee38f Mac Sequoia 15.6.1 arm64 VS Code Version: 1.103.1 (Universal) Go for Visual Studio Code 0.48.0

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: adonovan

The "unreadable could not read string at %X due to protocol error" message seems like a Delve (debugger) issue.

The fact that the debugger cannot read a string out of args.URL seems like a liveness issue: the compiler may have decided the args variable is no longer needed after the HTTP request and has reused the registers (or stack slot) for another purpose.