Hmbown/CodeWhale · error

LSP server must use UTF-16 positions

Error message

LSP server must use UTF-16 positions

What it means

The client requires UTF-16 (LSP default) position encoding. If the server advertises a `capabilities.positionEncoding` other than "utf-16", offsets computed by the client would disagree with the server's, so spawn fails rather than corrupt positions.

Solutions

  1. Request only utf-16 in client capabilities during initialize
  2. Reject or restart with a server that keeps default utf-16 encoding
  3. Implement utf-8/utf-32 offset conversion if you must support such servers

Example fix

// before
"capabilities": {"general": {"positionEncodings": ["utf-8", "utf-16"]}}
// after
"capabilities": {"general": {"positionEncodings": ["utf-16"]}}
Defensive patterns

Strategy: validation

Validate before calling

const enc = caps?.general?.positionEncodings ?? ['utf-16'];
if (!enc.includes('utf-16')) throw new Error('server does not support utf-16 positions');

Type guard

fn supports_utf16(v: &Value) -> bool {
    match v.pointer("/capabilities/positionEncoding") {
        None => true,
        Some(e) => e.as_str() == Some("utf-16"),
    }
}

Try / catch

match spawn_with_timeout(...).await {
    Err(e) if e.to_string().contains("UTF-16") => {
        eprintln!("configure server for utf-16 or pick a compatible server");
    }
    other => other,
}

Prevention

When it happens

Trigger: Server negotiates `positionEncoding` to "utf-8" or "utf-32" in its initialize response while the client only speaks utf-16.

Common situations: Newer servers (LSP 3.17+) supporting utf-8 encodings; misconfigured client capabilities requesting a non-utf-16 encoding; custom/specialty servers.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/32361fca84e2e04d. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/lsp/client.rs:296

            "rootUri": uri_from_path(&workspace),
            "capabilities": {
                "general": { "positionEncodings": ["utf-16"] },
                "textDocument": {
                    "publishDiagnostics": { "relatedInformation": false, "versionSupport": true }
                }
            },
            "workspaceFolders": [{"uri": uri_from_path(&workspace), "name": "workspace"}]
        }), initialize_wait).await.context("LSP initialization failed")?;
        if !result.get("capabilities").is_some_and(Value::is_object) {
            return Err(anyhow!(
                "LSP initialize response is missing server capabilities"
            ));
        }
        if result
            .pointer("/capabilities/positionEncoding")
            .is_some_and(|encoding| encoding.as_str() != Some("utf-16"))
        {
            return Err(anyhow!("LSP server must use UTF-16 positions"));
        }
        timeout(
            initialize_wait,
            send_message(
                &transport.tx_outbound,
                &json!({
                    "jsonrpc": "2.0", "method": "initialized", "params": {}
                }),
            ),
        )
        .await
        .map_err(|_| anyhow!("LSP initialized notification timed out"))??;
        Ok(transport)
    }
}

impl Drop for StdioLspTransport {
    fn drop(&mut self) {

View on GitHub (pinned to 73e0f67d83)