Description
Streams from Vertex AI partner models routed through the OpenAI-compatible
endpoint (e.g. xai/grok-4.6 via @ai-sdk/openai-compatible) abort after
15–30s of reasoning with:
AI_JSONParseError: JSON parsing failed: Text: : keepalive.
Error message: JSON Parse error: Unexpected token ':'
Root cause: on a long time-to-first-token the Vertex partner-model proxy emits
keepalives every ~13–15s as SSE data events — data: : keepalive\n\n —
instead of spec-legal comment lines : keepalive\n\n. parseJsonEventStream
drops the latter correctly, but treats the former as a data event and hands
: keepalive to JSON.parse(), killing the stream.
Both google-vertex fetch wrappers pass the body through untouched, so both
paths are affected:
packages/opencode/src/provider/provider.ts:542-552 (v1)
packages/core/src/plugin/provider/google-vertex.ts → authFetch() (v2)
Suggested fix: when content-type is text/event-stream, pipe the body
through a TransformStream that drops lines matching /^data:\s*:/ before the
SDK's SSE decoder sees them (dropping content-length/content-encoding on
the rebuilt Response). I have a working implementation with unit tests and
can open a PR if that's wanted.
Related but distinct: #43519 / #43618 (chunkTimeout vs well-formed comment
heartbeats — that stream parses fine and hangs, this one crashes the parser);
#13914 (Vertex vertex_event frame on the Anthropic path).
Plugins
Local workaround only: a vertex-keepalive.ts plugin wrapping globalThis.fetch
to strip these frames.
OpenCode version
1.18.30
Steps to reproduce
- Configure
google-vertex with an @ai-sdk/openai-compatible partner model,
e.g. xai/grok-4.6.
- Send a prompt large enough that the model reasons for >15s before the first token.
- The proxy emits
data: : keepalive and the stream dies with the error above.
Operating System
macOS 26.7
Terminal
Ghostty (tmux)
Description
Streams from Vertex AI partner models routed through the OpenAI-compatible
endpoint (e.g.
xai/grok-4.6via@ai-sdk/openai-compatible) abort after15–30s of reasoning with:
Root cause: on a long time-to-first-token the Vertex partner-model proxy emits
keepalives every ~13–15s as SSE data events —
data: : keepalive\n\n—instead of spec-legal comment lines
: keepalive\n\n.parseJsonEventStreamdrops the latter correctly, but treats the former as a data event and hands
: keepalivetoJSON.parse(), killing the stream.Both google-vertex fetch wrappers pass the body through untouched, so both
paths are affected:
packages/opencode/src/provider/provider.ts:542-552(v1)packages/core/src/plugin/provider/google-vertex.ts→authFetch()(v2)Suggested fix: when
content-typeistext/event-stream, pipe the bodythrough a
TransformStreamthat drops lines matching/^data:\s*:/before theSDK's SSE decoder sees them (dropping
content-length/content-encodingonthe rebuilt
Response). I have a working implementation with unit tests andcan open a PR if that's wanted.
Related but distinct: #43519 / #43618 (chunkTimeout vs well-formed comment
heartbeats — that stream parses fine and hangs, this one crashes the parser);
#13914 (Vertex
vertex_eventframe on the Anthropic path).Plugins
Local workaround only: a
vertex-keepalive.tsplugin wrappingglobalThis.fetchto strip these frames.
OpenCode version
1.18.30
Steps to reproduce
google-vertexwith an@ai-sdk/openai-compatiblepartner model,e.g.
xai/grok-4.6.data: : keepaliveand the stream dies with the error above.Operating System
macOS 26.7
Terminal
Ghostty (tmux)