Code of Conduct
On what operating system are you seeing the problem?
macOS (Apple/arm64)
VS Code version
Description:
Extension version: Latest (as of 2026-03-27)
VS Code version: 1.113.0 (macOS, Apple Silicon)
Docker Desktop version: Latest
Summary
The EventListener.readValuesFromStream() method in src/docker/eventListener.ts does not buffer partial reads from the Docker event stream, causing JSON parse failures when a single event payload exceeds the ReadableStream chunk size (~2KB). This prevents the extension from detecting running Kafka containers.
These come in pairs: the first chunk is an unterminated JSON string, and the second chunk is the orphaned tail — neither is valid JSON on its own.
Expected Behavior
The extension should correctly detect the running confluentinc/confluent-local container regardless of how many Docker/OCI labels are present on the image.
Root Cause
Docker's /events endpoint returns newline-delimited JSON (NDJSON). Each event is a complete JSON object followed by \n. However, ReadableStream.getReader().read() returns data at arbitrary byte boundaries determined by TCP/HTTP chunking — not aligned to newline boundaries.
The current implementation in readValuesFromStream() decodes each chunk, splits on \n, and yields every fragment immediately:
When an event payload is larger than the read buffer (~2KB), it gets split across two read() calls. The tail of chunk N and the head of chunk N+1 are each yielded as separate strings. JSON.parse() then fails on both.
Containers with many labels (e.g., confluentinc/confluent-local which includes Confluent, Red Hat UBI, OCI, and Docker Compose labels) reliably produce events exceeding 2KB, triggering this bug consistently.
Proposed Fix
Buffer partial lines across reads and only yield complete lines (those terminated by \n):
Key changes:
A buffer string carries over incomplete data between reads
After split("\n"), lines.pop() retains the last element (which may lack a trailing \n and therefore be incomplete)
Only complete lines — those followed by a \n delimiter — are yielded
On stream end (done === true), any remaining buffer content is flushed
This is the standard pattern for consuming NDJSON over a ReadableStream. The fix is backwards-compatible — it changes no public API and the handleEvent() caller receives the same strings, just correctly reassembled.
Workaround
As a temporary workaround, users can configure the extension to match their container's exact image tag to ensure the ancestor filter works, and restart the container after VS Code launches. However, this does not fix the parse errors — it just increases the chance of the start event being small enough to fit in a single chunk.
Version of Confluent extension
v2.2.2
To Reproduce
Run a confluentinc/confluent-local:latest container via Docker Compose with many labels (Compose metadata + OCI image labels combine to produce events > 2KB)
Open VS Code with the Confluent extension
The extension fails to detect the container — no local Kafka cluster appears in the sidebar
Current vs. Expected behavior
Observed Behavior
The Output panel (Confluent channel) shows repeated errors like:
These come in pairs: the first chunk is an unterminated JSON string, and the second chunk is the orphaned tail — neither is valid JSON on its own.
Expected Behavior
The extension should correctly detect the running confluentinc/confluent-local container regardless of how many Docker/OCI labels are present on the image.
Relevant log output
2026-03-27 20:09:22.391 [error] [docker.eventListener] error parsing event {"error":"Unexpected token 'i', \"images.\",\"\"... is not valid JSON","eventString":"images.\",\"desktop.docker.io/ports.scheme\":\"v2\",\"desktop.docker.io/ports/9092/tcp\":\":9092\",\"distribution-scope\":\"public\",\"execID\":\"b5e209326ca1a15ed7205b88c5c9bdef41f59433ba23c27f2752fb030a049b51\",\"image\":\"confluentinc/confluent-local:latest\",\"io.buildah.version\":\"1.42.2\",\"io.confluent.docker\":\"true\",\"io.confluent.docker.build.number\":\"f2ed3370\",\"io.confluent.docker.git.id\":\"7113046\",\"io.confluent.docker.git.repo\":\"confluentinc/kafka-images\",\"io.k8s.description\":\"The Universal Base Image Minimal is a stripped down image that uses microdnf as a package manager. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.\",\"io.k8s.display-name\":\"Red Hat Universal Base Image 9 Minimal\",\"io.openshift.expose-services\":\"\",\"io.openshift.tags\":\"minimal rhel9\",\"maintainer\":\"partner-support@confluent.io\",\"name\":\"kafka\",\"org.opencontainers.image.created\":\"2026-02-17T16:45:31Z\",\"org.opencontainers.image.revision\":\"0ced2bbee24d5463d4530756a57f8db895246c48\",\"release\":\"8.2.0-68\",\"summary\":\"Kafka with Rest Proxy\",\"url\":\"https://catalog.redhat.com/en/search?searchType=containers\",\"vcs-ref\":\"0ced2bbee24d5463d4530756a57f8db895246c48\",\"vcs-type\":\"git\",\"vendor\":\"Confluent\",\"version\":\"7113046\"},\"ID\":\"21e248a847653e31cf0fa7cb9232e2d66d9b6ed49cb6d67b5a80283fc7b0eb7c\"},\"Type\":\"container\",\"from\":\"confluentinc/confluent-local:latest\",\"id\":\"21e248a847653e31cf0fa7cb9232e2d66d9b6ed49cb6d67b5a80283fc7b0eb7c\",\"scope\":\"local\",\"status\":\"exec_start: /bin/sh -c kafka-topics --bootstrap-server localhost:9092 --list\",\"time\":1774638562,\"timeNano\":1774638562385722000}"}
Which area(s) are affected? (Select all that apply)
Local
Additional context
Root Cause
Docker's /events endpoint returns newline-delimited JSON (NDJSON). Each event is a complete JSON object followed by \n. However, ReadableStream.getReader().read() returns data at arbitrary byte boundaries determined by TCP/HTTP chunking — not aligned to newline boundaries.
The current implementation in readValuesFromStream() decodes each chunk, splits on \n, and yields every fragment immediately:
When an event payload is larger than the read buffer (~2KB), it gets split across two read() calls. The tail of chunk N and the head of chunk N+1 are each yielded as separate strings. JSON.parse() then fails on both.
Containers with many labels (e.g., confluentinc/confluent-local which includes Confluent, Red Hat UBI, OCI, and Docker Compose labels) reliably produce events exceeding 2KB, triggering this bug consistently.
Proposed Fix
Buffer partial lines across reads and only yield complete lines (those terminated by \n):
async *readValuesFromStream(
stream: ReadableStream<Uint8Array>,
maxWaitTimeSec?: number,
): AsyncGenerator<string> {
logger.debug("reading from stream...");
const reader: ReadableStreamDefaultReader<Uint8Array> = stream.getReader();
const decoder = new TextDecoder();
const startTime = Date.now();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) {
// Flush any remaining buffered data
const remaining = buffer.trim();
if (remaining) {
yield remaining;
}
logger.debug("stream ended");
break;
}
if (this.stopped) {
logger.warn("listener stopped, exiting early");
break;
}
if (!value) {
logger.debug("got empty value from stream");
continue;
}
// Append decoded chunk to the carry-over buffer
buffer += decoder.decode(value, { stream: true });
// Split on newlines; the last element may be incomplete
const lines = buffer.split("\n");
buffer = lines.pop() ?? ""; // Keep the incomplete tail for the next read
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
yield trimmed;
}
if (
maxWaitTimeSec !== undefined &&
Date.now() - startTime > maxWaitTimeSec * 1000
) {
logger.debug("max wait time reached, exiting stream reader");
break;
}
}
}
Key changes:
A buffer string carries over incomplete data between reads
After split("\n"), lines.pop() retains the last element (which may lack a trailing \n and therefore be incomplete)
Only complete lines — those followed by a \n delimiter — are yielded
On stream end (done === true), any remaining buffer content is flushed
This is the standard pattern for consuming NDJSON over a ReadableStream. The fix is backwards-compatible — it changes no public API and the handleEvent() caller receives the same strings, just correctly reassembled.
Workaround
As a temporary workaround, users can configure the extension to match their container's exact image tag to ensure the ancestor filter works, and restart the container after VS Code launches. However, this does not fix the parse errors — it just increases the chance of the start event being small enough to fit in a single chunk.
Code of Conduct
On what operating system are you seeing the problem?
macOS (Apple/arm64)
VS Code version
Description:
Extension version: Latest (as of 2026-03-27)
VS Code version: 1.113.0 (macOS, Apple Silicon)
Docker Desktop version: Latest
Summary
The EventListener.readValuesFromStream() method in src/docker/eventListener.ts does not buffer partial reads from the Docker event stream, causing JSON parse failures when a single event payload exceeds the ReadableStream chunk size (~2KB). This prevents the extension from detecting running Kafka containers.
These come in pairs: the first chunk is an unterminated JSON string, and the second chunk is the orphaned tail — neither is valid JSON on its own.
Expected Behavior
The extension should correctly detect the running confluentinc/confluent-local container regardless of how many Docker/OCI labels are present on the image.
Root Cause
Docker's /events endpoint returns newline-delimited JSON (NDJSON). Each event is a complete JSON object followed by \n. However, ReadableStream.getReader().read() returns data at arbitrary byte boundaries determined by TCP/HTTP chunking — not aligned to newline boundaries.
The current implementation in readValuesFromStream() decodes each chunk, splits on \n, and yields every fragment immediately:
When an event payload is larger than the read buffer (~2KB), it gets split across two read() calls. The tail of chunk N and the head of chunk N+1 are each yielded as separate strings. JSON.parse() then fails on both.
Containers with many labels (e.g., confluentinc/confluent-local which includes Confluent, Red Hat UBI, OCI, and Docker Compose labels) reliably produce events exceeding 2KB, triggering this bug consistently.
Proposed Fix
Buffer partial lines across reads and only yield complete lines (those terminated by \n):
Key changes:
A buffer string carries over incomplete data between reads
After split("\n"), lines.pop() retains the last element (which may lack a trailing \n and therefore be incomplete)
Only complete lines — those followed by a \n delimiter — are yielded
On stream end (done === true), any remaining buffer content is flushed
This is the standard pattern for consuming NDJSON over a ReadableStream. The fix is backwards-compatible — it changes no public API and the handleEvent() caller receives the same strings, just correctly reassembled.
Workaround
As a temporary workaround, users can configure the extension to match their container's exact image tag to ensure the ancestor filter works, and restart the container after VS Code launches. However, this does not fix the parse errors — it just increases the chance of the start event being small enough to fit in a single chunk.
Version of Confluent extension
v2.2.2
To Reproduce
Run a confluentinc/confluent-local:latest container via Docker Compose with many labels (Compose metadata + OCI image labels combine to produce events > 2KB)
Open VS Code with the Confluent extension
The extension fails to detect the container — no local Kafka cluster appears in the sidebar
Current vs. Expected behavior
Observed Behavior
The Output panel (Confluent channel) shows repeated errors like:
These come in pairs: the first chunk is an unterminated JSON string, and the second chunk is the orphaned tail — neither is valid JSON on its own.
Expected Behavior
The extension should correctly detect the running confluentinc/confluent-local container regardless of how many Docker/OCI labels are present on the image.
Relevant log output
2026-03-27 20:09:22.391 [error] [docker.eventListener] error parsing event {"error":"Unexpected token 'i', \"images.\",\"\"... is not valid JSON","eventString":"images.\",\"desktop.docker.io/ports.scheme\":\"v2\",\"desktop.docker.io/ports/9092/tcp\":\":9092\",\"distribution-scope\":\"public\",\"execID\":\"b5e209326ca1a15ed7205b88c5c9bdef41f59433ba23c27f2752fb030a049b51\",\"image\":\"confluentinc/confluent-local:latest\",\"io.buildah.version\":\"1.42.2\",\"io.confluent.docker\":\"true\",\"io.confluent.docker.build.number\":\"f2ed3370\",\"io.confluent.docker.git.id\":\"7113046\",\"io.confluent.docker.git.repo\":\"confluentinc/kafka-images\",\"io.k8s.description\":\"The Universal Base Image Minimal is a stripped down image that uses microdnf as a package manager. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.\",\"io.k8s.display-name\":\"Red Hat Universal Base Image 9 Minimal\",\"io.openshift.expose-services\":\"\",\"io.openshift.tags\":\"minimal rhel9\",\"maintainer\":\"partner-support@confluent.io\",\"name\":\"kafka\",\"org.opencontainers.image.created\":\"2026-02-17T16:45:31Z\",\"org.opencontainers.image.revision\":\"0ced2bbee24d5463d4530756a57f8db895246c48\",\"release\":\"8.2.0-68\",\"summary\":\"Kafka with Rest Proxy\",\"url\":\"https://catalog.redhat.com/en/search?searchType=containers\",\"vcs-ref\":\"0ced2bbee24d5463d4530756a57f8db895246c48\",\"vcs-type\":\"git\",\"vendor\":\"Confluent\",\"version\":\"7113046\"},\"ID\":\"21e248a847653e31cf0fa7cb9232e2d66d9b6ed49cb6d67b5a80283fc7b0eb7c\"},\"Type\":\"container\",\"from\":\"confluentinc/confluent-local:latest\",\"id\":\"21e248a847653e31cf0fa7cb9232e2d66d9b6ed49cb6d67b5a80283fc7b0eb7c\",\"scope\":\"local\",\"status\":\"exec_start: /bin/sh -c kafka-topics --bootstrap-server localhost:9092 --list\",\"time\":1774638562,\"timeNano\":1774638562385722000}"}Which area(s) are affected? (Select all that apply)
Local
Additional context
Root Cause
Docker's /events endpoint returns newline-delimited JSON (NDJSON). Each event is a complete JSON object followed by \n. However, ReadableStream.getReader().read() returns data at arbitrary byte boundaries determined by TCP/HTTP chunking — not aligned to newline boundaries.
The current implementation in readValuesFromStream() decodes each chunk, splits on \n, and yields every fragment immediately:
When an event payload is larger than the read buffer (~2KB), it gets split across two read() calls. The tail of chunk N and the head of chunk N+1 are each yielded as separate strings. JSON.parse() then fails on both.
Containers with many labels (e.g., confluentinc/confluent-local which includes Confluent, Red Hat UBI, OCI, and Docker Compose labels) reliably produce events exceeding 2KB, triggering this bug consistently.
Proposed Fix
Buffer partial lines across reads and only yield complete lines (those terminated by \n):
Key changes:
A buffer string carries over incomplete data between reads
After split("\n"), lines.pop() retains the last element (which may lack a trailing \n and therefore be incomplete)
Only complete lines — those followed by a \n delimiter — are yielded
On stream end (done === true), any remaining buffer content is flushed
This is the standard pattern for consuming NDJSON over a ReadableStream. The fix is backwards-compatible — it changes no public API and the handleEvent() caller receives the same strings, just correctly reassembled.
Workaround
As a temporary workaround, users can configure the extension to match their container's exact image tag to ensure the ancestor filter works, and restart the container after VS Code launches. However, this does not fix the parse errors — it just increases the chance of the start event being small enough to fit in a single chunk.