DopplerHQ / DopplerHQ/cli

doppler run --watch: SSE keepalive frames fail to parse — "unexpected end of JSON input" every ~30s

Open
#536 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
396
Forks
83
Avg merge
1d 2h
Merged PRs (30d)
3

Description

Summary

When running doppler run --watch, the CLI logs Doppler Error: unexpected end of JSON input on a ~30s cadence. With --debug enabled you can see it is the analytics event WatchDataParseError firing twice per cycle, with error: "invalid length" and error: "invalid data json". The initial secret fetch and the watched child process are unaffected — it is purely the --watch stream reader.

Version: doppler CLI v3.76.0 (latest)

The server stream is well-formed

Hitting the watch endpoint directly (GET /v3/configs/config/secrets/watch) returns valid SSE:

event: message
data: {"type":"connected"}

event: message
data: {"type":"ping"}        <- every ~30s

So the server side is fine; the failure is client-side in how the stream is read.

Root cause

In performSSERequest (pkg/http), the response body is read with a fixed 1024-byte buffer via repeated response.Body.Read(), and each raw chunk (data[:n]) is passed straight to the watch handler / ParseWatchEvent — with no SSE frame reassembly (no accumulation to the \n\n event boundary, no data: field extraction across reads).

When the server delivers a single SSE event across more than one read — which the periodic keepalive does — each partial fragment is handed to the JSON parser on its own and fails. That matches the two parse errors observed per cycle (invalid length + invalid data json).

Impact

  • Continuous error-log noise (~once per keepalive) for any doppler run --watch.
  • secrets.update events go through the same reader, so live secret-reload is unreliable: whether an update is honored depends on whether its frame happens to land within a single read.

Suggested fix

Buffer reads and split on SSE event boundaries (\n\n), extract the data: payload, and only hand complete frames to the parser.

Reproduction

  1. doppler run --watch -- <any process> against a config (reproduces with a service token).
  2. Watch stderr for ~1 minute; the error appears on each keepalive (~30s).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in pkg/http at performSSERequest and follow how raw response reads reach the watch handler and ParseWatchEvent. Reproduce with doppler run --watch and observe the keepalive errors for about a minute. Done means complete SSE frames are parsed at event boundaries, keepalives no longer log JSON errors, and secrets.update events remain reliable.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.