-
Notifications
You must be signed in to change notification settings - Fork 1.8k
BOM character (U+FEFF) in telemetry.devDeviceId causes 'Language model unavailable' — all API requests fail with ByteString error #4908
Description
Bug Report
Environment
- VS Code: 1.113.0 (arm64)
- GitHub Copilot Chat: v0.42.2
- OS: macOS 26.3.1 (Apple Silicon)
Problem
The Chat panel shows "Language model unavailable" and no language models can be resolved. All Copilot API requests fail silently.
Root Cause
The file ~/Library/Application Support/Code/User/globalStorage/storage.json contained a Unicode BOM character (U+FEFF, hex EF BB BF) prepended to the telemetry.devDeviceId value:
"telemetry.devDeviceId": "\uFEFFdeec2157-6fb9-4d61-b623-f5bc5131e91a"The Copilot Chat extension reads this value and includes it as an HTTP header in API requests. Since U+FEFF (char code 65279) exceeds the ByteString limit of 255, Node.js's undici HTTP library rejects every request with:
TypeError: Cannot convert argument to a ByteString because the character at index 0 has a value of 65279 which is greater than 255.
Impact — Cascading failures
This single corrupted byte broke all Copilot functionality:
_fetchModels→ "Failed to fetch models" → cannot discover available modelsgetCopilotAgentModels→ remote agent loading failsgetAllSessions→ chat session history fails to load- Model resolution →
Unable to resolve chat model with family selection: gpt-4o-mini - Final result → "Language model unavailable" in the Chat panel
How to Reproduce
- Close VS Code
- Edit
~/Library/Application Support/Code/User/globalStorage/storage.json - Add a BOM (
\uFEFF) before the UUID intelemetry.devDeviceId - Open VS Code → Open Copilot Chat → Send any message
- Observe "Language model unavailable"
Fix Applied (manual workaround)
Removed the BOM from the telemetry.devDeviceId value in storage.json. After restarting VS Code, all models resolved correctly (claude-opus-4.5, gpt-4o-mini, etc.).
Suggested Improvements
- Sanitize header values: Strip BOM/non-ASCII characters from values read from
storage.jsonbefore using them as HTTP headers. A simple.replace(/\uFEFF/g, '')would prevent this class of failure. - Validate on write: When writing
telemetry.devDeviceId, ensure the value is a clean UUID without invisible characters. - Better error reporting: Instead of silently failing all requests and showing "Language model unavailable", surface the actual
ByteStringerror to the user in the Output panel so it can be diagnosed. - Graceful degradation: If the device ID header fails, fall back to a request without it rather than blocking all functionality.
Logs
Extension Host log (before fix):
TypeError: Cannot convert argument to a ByteString because the character at index 0 has a value of 65279 which is greater than 255.
Extension Host log (after fix):
ccreq:ee04c8dc | success | claude-opus-4-5-20251101 | 3592ms | [panel/editAgent]
ccreq:862717e5 | success | gpt-4o-mini-2024-07-18 | 418ms | [copilotLanguageModelWrapper]
Unknown
I don't know how the BOM got into storage.json in the first place. It may have been introduced by another extension, a file sync tool, or a VS Code update. It would be worth investigating whether VS Code core or another component could be writing BOM-prefixed values to this file.