Describe the bug
gh cs ports forward crashes with a Go runtime fatal error (concurrent map writes) when forwarding multiple ports simultaneously. This is a race condition where multiple goroutines write to an unsynchronized map concurrently.
Steps to reproduce
- Have a running codespace
- Forward multiple ports in a single command:
gh cs ports forward 80:80 8080:8080 3930:3930 -c <codespace-name>
- The command crashes intermittently
Expected vs actual behavior
Expected: All ports forward successfully.
Actual: The process crashes. On repeated attempts, different errors surface:
fatal error: concurrent map writes (race condition, most common)
error forwarding port: create tunnel port failed: ... 400: Bad Request
error connecting to tunnel: ... ssh: rejected: connect failed (Connection refused)
Stack trace
goroutine 99 [running]:
github.com/microsoft/dev-tunnels/go/tunnels.(*Manager).CreateTunnelPort(...)
github.com/microsoft/dev-tunnels@v0.1.19/go/tunnels/manager.go:452 +0xcc
github.com/cli/cli/v2/internal/codespaces/portforwarder.(*CodespacesPortForwarder).ForwardPort(...)
.../port_forwarder.go:164 +0x280
github.com/cli/cli/v2/pkg/cmd/codespace.(*App).ForwardPorts.func1()
.../codespace/ports.go:349 +0x25c
golang.org/x/sync/errgroup.(*Group).Go.func1()
Possible cause
ports.go:349 launches concurrent goroutines via errgroup.Go for each port. These all call CreateTunnelPort on the same Manager instance, which writes to a shared map without synchronization.
Describe the bug
gh cs ports forwardcrashes with a Go runtime fatal error (concurrent map writes) when forwarding multiple ports simultaneously. This is a race condition where multiple goroutines write to an unsynchronized map concurrently.Steps to reproduce
Expected vs actual behavior
Expected: All ports forward successfully.
Actual: The process crashes. On repeated attempts, different errors surface:
fatal error: concurrent map writes(race condition, most common)error forwarding port: create tunnel port failed: ... 400: Bad Requesterror connecting to tunnel: ... ssh: rejected: connect failed (Connection refused)Stack trace
Possible cause
ports.go:349launches concurrent goroutines viaerrgroup.Gofor each port. These all callCreateTunnelPorton the sameManagerinstance, which writes to a shared map without synchronization.