Repository navigation
x/tools/gopls: "Create variable" declares x := nil or x := 0 where the use needs another type #81808
Description
gopls version
golang.org/x/tools/gopls v0.23.0 (h1:Dn6mf9WXu9iLnTftDDMb9wV0c6Se7PjzEMqP0LEe08Y=), built with go1.27.1.
v0.23.0 is still the newest gopls release (checked 2026-09-28); all five cases reproduce on it again in 3 of 3 runs.
Same results with gopls v0.20.0.
go env
GOARCH=arm64
GOOS=darwin
GOVERSION=go1.27.1
GOFLAGS=-modcacherw
GOTOOLCHAIN=local(macOS 27 on Apple silicon; path variables left out.)
What did you do?
I drive gopls over LSP from a small script. In five public projects I misspelled one use of a name, which gives undefined: X (UndeclaredName), and applied the quick fix "Create variable X". Each file builds before the typo. Line numbers are 1-based.
-
spf13/cobra at adbc8813901bba65827259daa8e22ff94ec1f30e, command_win.go (a Windows-only file; gopls reports it with
[windows,amd64]),MousetrapHelpTextmisspelled on line 32:func preExecHook(c *Command) { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { c.Print(MousetrappHelpText)
"Create variable MousetrappHelpText" inserts
MousetrappHelpText := nilabove line 32. -
XTLS/Xray-core at d562d8947d3175db86b4fa849742433a9876cb63, common/crypto/io.go,
readermisspelled in a struct field of typeio.Reader:func NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader { return &CryptionReader{ stream: stream, reader: reaer, } }
"Create variable reaer" inserts
reaer := 0as the first line of the function. -
charmbracelet/bubbletea at 657aaae216e3f87df09b60959a9fe5de7b2ca419, examples/list-default/main.go (module
examples), the type namemodelmisspelled in a composite literal:m := moddel{list: list.New(items, list.NewDefaultDelegate(), 0, 0)}
"Create variable moddel" inserts
moddel := 0above it. -
caddyserver/caddy at c18099a0af5e88c8d9da0b9d797f6f2c62d60a23, modules/caddyhttp/reverseproxy/selectionpolicies_test.go line 126,
poool[1].countRequest(1): the fix insertspoool := 0. -
nektos/act at 4f411281417e88660bea1c1a1749aa71ae0bd60f, pkg/container/docker_auth.go line 29,
strings.ContainsAny(imge[:index], ".:"): the fix insertsimge := 0.
What did you see happen?
In every case the fix removes undefined: X and the file gets a different compile error instead (gopls publishes it right after the edit; the lines below are from go build, or go vet for the test file):
| case | inserted | error after the fix |
|---|---|---|
1 cobra (GOOS=windows GOARCH=amd64 go build .) |
MousetrappHelpText := nil |
./command_win.go:32:25: use of untyped nil in assignment |
| 2 Xray-core | reaer := 0 |
common/crypto/io.go:19:11: cannot use reaer (variable of type int) as io.Reader value in struct literal: int does not implement io.Reader (missing method Read) |
| 3 bubbletea | moddel := 0 |
list-default/main.go:80:7: moddel (local variable) is not a type |
4 caddy (go vet) |
poool := 0 |
modules/caddyhttp/reverseproxy/selectionpolicies_test.go:127:2: cannot index poool (variable of type int) |
| 5 act | imge := 0 |
pkg/container/docker_auth.go:30:40: cannot slice imge (variable of type int) |
Each case reproduced in 3 of 3 runs.
What did you expect to see?
The docs say the fix inserts "a declaration with a default value inferring its type from the context". So:
- case 1:
Printis declared asPrint(i ...interface{}), so the context type isinterface{}, andx := nilnever compiles; something likevar MousetrappHelpText interface{}would. - case 2: the context type is
io.Reader(the struct field), sovar reaer io.Reader. - case 3: the name is used as a type, so no variable can fix it; I expected no "Create variable" action there.
- cases 4 and 5: I don't know what type could be inferred, but
:= 0cannot be indexed or sliced, so the fix only trades one error for another.
Editor and settings
No editor; a script over stdio (gopls serve). Settings returned for workspace/configuration: {"semanticTokens": true, "hints": {"assignVariableTypes": true, "compositeLiteralFields": true, "compositeLiteralTypes": true, "constantValues": true, "functionTypeParameters": true, "parameterNames": true, "rangeVariableTypes": true}}.
Logs
LSP trace (case 1)
F stands for the URI of command_win.go; positions are 0-based.
--> textDocument/didChange {"textDocument":{"uri":F,"version":2},"contentChanges":[{"range":{"start":{"line":31,"character":10},"end":{"line":31,"character":27}},"text":"MousetrappHelpText"}]}
<-- textDocument/publishDiagnostics {"uri":F,"version":2,"diagnostics":[{"range":{"start":{"line":31,"character":10},"end":{"line":31,"character":28}},"severity":1,"code":"UndeclaredName","source":"compiler","message":"undefined: MousetrappHelpText [windows,amd64]"}]}
--> textDocument/codeAction {"textDocument":{"uri":F},"range":{"start":{"line":31,"character":10},"end":{"line":31,"character":28}},"context":{"diagnostics":[(the diagnostic above)],"only":["quickfix"],"triggerKind":1}}
<-- [{"title":"Create variable MousetrappHelpText","kind":"quickfix","data":{"title":"Create variable MousetrappHelpText","command":"gopls.apply_fix",
"arguments":[{"Fix":"create_undeclared","Location":{"uri":F,"range":{"start":{"line":31,"character":10},"end":{"line":31,"character":28}}},"ResolveEdits":true}]}}]
--> codeAction/resolve (that action)
<-- {"title":"Create variable MousetrappHelpText","kind":"quickfix","edit":{"documentChanges":[{"textDocument":{"version":2,"uri":F},
"edits":[{"range":{"start":{"line":31,"character":2},"end":{"line":31,"character":2}},"newText":"MousetrappHelpText := nil\n\t\t"}]}]}}
--> textDocument/didChange (the edit above, version 3)
<-- textDocument/publishDiagnostics {"uri":F,"version":3,"diagnostics":[{"range":{"start":{"line":31,"character":24},"end":{"line":31,"character":27}},"severity":1,"code":"UntypedNilUse","source":"compiler","message":"use of untyped nil in assignment [windows,amd64]"}]}
Activity
gabyhelp commentedon Sep 28, 2026
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
wangzhihao-lab commentedon Sep 28, 2026
Case 3 (the misspelled type name in the composite literal,
moddel{...}) is the case reported in #69947. The other four cases are about the inserted zero value (nil,0) not matching the type the use needs.gopherbot commentedon Oct 1, 2026
Change https://go.dev/cl/842926 mentions this issue:
gopls/internal/golang: test Create variable in bad contextsgopls/internal/golang: test Create variable in bad contexts
gopherbot commentedon Oct 5, 2026
Change https://go.dev/cl/845405 mentions this issue:
gopls/internal/golang: replace assignment with declarationgopls/internal/golang: use decl over assignment for undeclared var