Skip to content

gopls LSP tools broken — symbols never spawns server, document-symbols/diagnostics have path handling bugs #15314

@zztdandan

Description

@zztdandan

Description

[Bug]: gopls LSP tools broken — symbols never spawns server, document-symbols/diagnostics have path handling bugs

Prerequisites

  • I have searched existing issues to avoid duplicates
  • I am using the latest version of OpenCode
  • I have tested with opencode debug lsp commands and collected full logs

Environment

  • OpenCode: v1.2.10
  • gopls: v0.21.1 (golang.org/x/tools/gopls)
  • Go: go1.24.1 linux/amd64
  • OS: Linux (Ubuntu)

Summary

Three distinct bugs in OpenCode's LSP integration with gopls:

  1. symbols (workspace symbols) never spawns gopls — returns empty [] in 1ms without ever starting the LSP server
  2. document-symbols crashes with relative pathTypeError: The URL must be of scheme file at src/lsp/index.ts:372
  3. diagnostics with file:// URI has path concatenation bug — produces invalid path like /home/user/project/file:/home/user/project/main.go

During agent sessions, these bugs manifest as Error: no views for all LSP tools except diagnostics (which partially works with relative paths only).

opencode.json (LSP config)

{
  "$schema": "https://opencode.ai/config.json",
  "lsp": {
    "gopls": {
      "command": [
        "/path/to/gopath/bin/gopls"
      ],
      "env": {
        "PATH": "/path/to/go/bin:/usr/local/bin:/usr/bin:/bin",
        "GOROOT": "/path/to/go",
        "GOPATH": "/path/to/gopath",
        "GOMODCACHE": "/path/to/gopath/pkg/mod",
        "GOPROXY": "https://goproxy.cn,direct",
        "GO111MODULE": "on",
        "GOTOOLCHAIN": "auto"
      },
      "extensions": [
        ".go"
      ],
      "initialization": {}
    }
  }
}

Reproduction & Test Results

Test 1: diagnostics with relative path — ✅ Works

$ opencode debug lsp diagnostics ./main.go
{
  "/home/user/project/main.go": []
}

Debug log confirms gopls is spawned correctly:

service=lsp  file=./main.go touching file
service=lsp  serverID=gopls spawned lsp server
service=lsp.client  serverID=gopls sending initialize
service=lsp.client  serverID=gopls initialized
service=lsp.client  textDocument/didOpen
service=lsp.client  count=0 textDocument/publishDiagnostics
service=lsp.client  got diagnostics    ← SUCCESS

Test 2: diagnostics with file:// URI — ❌ Path concatenation bug

$ opencode debug lsp diagnostics file:///home/user/project/main.go --print-logs --log-level DEBUG
{}

Debug log shows the bug — file:// URI is concatenated with project root:

service=lsp  file=file:///home/user/project/main.go touching file
service=lsp.client  path=/home/user/project/file:/home/user/project/main.go waiting for diagnostics
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                         BUG: project root prepended to file:// URI

ERROR service=lsp  err=ENOENT: no such file or directory,
  open '/home/user/project/file:/home/user/project/main.go'
  failed to touch file

Test 3: document-symbols with relative path — ❌ TypeError crash

$ opencode debug lsp document-symbols ./main.go
Error: Unexpected error
The URL must be of scheme file

Stack trace:

TypeError: The URL must be of scheme file
    at fileURLToPath (unknown)
    at documentSymbol (src/lsp/index.ts:372:18)
    at <anonymous> (src/cli/cmd/debug/lsp.ts:48:33)

Test 4: document-symbols with file:// URI — ✅ Works

$ opencode debug lsp document-symbols file:///home/user/project/main.go
[
  {
    "location": {
      "uri": "file:///home/user/project/main.go",
      "range": { "start": { "line": 11, "character": 0 }, "end": { "line": 37, "character": 1 } }
    },
    "name": "main",
    "kind": 12
  }
]

Also tested on another file with multiple symbols — works correctly:

$ opencode debug lsp document-symbols file:///home/user/project/global/start_type.go
[
  { "name": "StartServerType", "kind": 5 },
  { "name": "START_SERVER_NORMAL", "kind": 14 },
  { "name": "START_SERVER_INIT", "kind": 14 }
]

Test 5: symbols (workspace symbols) — ❌ Never spawns gopls

$ opencode debug lsp symbols main --print-logs --log-level DEBUG
[]

Debug log shows no gopls spawn at all — returns in 1ms:

service=default  status=started symbols
[]
service=default  status=completed duration=1 symbols    ← 1ms! No gopls interaction

Compare with diagnostics which takes ~1000ms because it actually spawns and queries gopls.

Also tested with a specific function name:

$ opencode debug lsp symbols StartNewServer
[]

Same result — empty array, no gopls spawn.

Root Cause Analysis

Bug 1: symbols never spawns gopls

The workspace/symbol code path does not trigger the "ensure server ready" flow. It queries for an already-running LSP server, finds none, and immediately returns [].

The diagnostics code path correctly does: touch file → spawn gopls → initialize → didOpen → wait for results. The symbols and other tools skip this entirely.

Bug 2: document-symbols path handling

src/lsp/index.ts:372 calls fileURLToPath() which requires a file:// URI. When a relative path like ./main.go is passed, it throws TypeError. The CLI should normalize the input path to a file:// URI before calling this function.

Bug 3: diagnostics file URI handling

When a file:// URI is passed to diagnostics, the touch-file logic prepends the project root directory to the full URI string, producing an invalid path:

/home/user/project/ + file:///home/user/project/main.go
= /home/user/project/file:/home/user/project/main.go   ← ENOENT

Impact on Agent Sessions

During agent sessions (LLM tool calls), these bugs cause:

LSP Tool Result
lsp_diagnostics ⚠️ Returns warning "No active builds contain..."
lsp_goto_definition Error: no views
lsp_find_references Error: no views
lsp_symbols (document) Error: no views
lsp_symbols (workspace) No symbols found (empty [])
lsp_prepare_rename Error: no views

This means gopls provides zero semantic intelligence to the LLM agent — no go-to-definition, no find-references, no symbols, no rename support. Only ast-grep (which doesn't use gopls) works.

Expected Behavior

All LSP tools should ensure gopls is spawned, initialized, and has opened the target file before querying. The path normalization should handle both relative paths and file:// URIs consistently.

Suggested Fix

  1. Unified "ensure server ready" flow: All LSP tool code paths (not just diagnostics) should trigger: spawn server → initialize → didOpen → then query.
  2. Path normalization: Normalize input to absolute path first, then convert to file:// URI where needed. Never concatenate project root with a file:// URI string.
  3. symbols should spawn gopls: The workspace symbol query needs a running LSP server. It should trigger gopls spawn (perhaps by opening any .go file) before sending workspace/symbol.

Plugins

oh-my-opencode, opencode-anthropic-auth@0.0.13

OpenCode version

v1.2.10

Steps to reproduce

  1. Configure gopls in opencode.json with custom env (GOROOT, GOPATH, etc.) i have past my config above
  2. Run opencode debug lsp symbols main → returns empty [] in 1ms, gopls never spawned
  3. Run opencode debug lsp document-symbols ./main.go → TypeError crash
  4. Run opencode debug lsp diagnostics file:///path/to/main.go → path concatenation bug, returns {}
  5. Run opencode debug lsp document-symbols file:///path/to/main.go → works correctly
  6. Run opencode debug lsp diagnostics ./main.go → works correctly

Screenshot and/or share link

No response

Operating System

Ubuntu

Terminal

vscode terminal

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions