Summary
Pasting an image into a Kilo Cloud Agent thread (kilo.ai web app) shows a preview in the composer, but after submitting, the message instead contains:
attachment a7393f97-c6bf-4c1f-9fec-2bbb11987962.png could not be retrieved (undefined is not a function)
The agent then "carries on" without the image. Reproduced with different UUIDs (e.g. 4024b67d-4294-4493-8884-ce0f9f40b836.png) in separate sessions — the image is silently dropped and the model never sees it.
Diagnosis
The string is generated by services/cloud-agent-next/wrapper/src/session-bootstrap.ts (downloadAndMaterializeAttachment): when the wrapper in the sandbox fetches the presigned R2 attachment URL, any fetch/read error is interpolated verbatim into a synthetic text part:
text: `attachment ${attachment.filename} could not be retrieved (${message})`
So (undefined is not a function) is a raw JS TypeError message leaking into the user-visible transcript. It matches a known class of Bun Web Streams bugs where reading a fetch() response body whose bytes arrive after the response head throws exactly TypeError: undefined is not a function (see oven-sh/bun#34302, #28952, #28953). I reproduced the exact message 100/100 times on Bun 1.3.12 by iterating a delayed-body Response.body; the failure is intermittent in production and depends on network latency + runtime version.
Impact
- Pasted images are lost without the user being told anything actionable.
- The raw internal error message (
undefined is not a function) is meaningless to users and agents.
- No retry exists, so a transient network/stream race permanently drops the attachment.
Proposed fix
PR (once open): https://github.com/Kilo-Org/cloud/pull/XXXX
- Retry transient attachment-download failures (3 attempts, short backoff).
- On retry, re-fetch and read the body with
response.arrayBuffer() (the workaround the Bun maintainers verified never hits the stream race) when content-length is bounded.
- On exhaustion, surface
attachment <name> could not be retrieved (download failed after N attempts) and log the raw reason instead of leaking raw JS errors.
Summary
Pasting an image into a Kilo Cloud Agent thread (kilo.ai web app) shows a preview in the composer, but after submitting, the message instead contains:
The agent then "carries on" without the image. Reproduced with different UUIDs (e.g.
4024b67d-4294-4493-8884-ce0f9f40b836.png) in separate sessions — the image is silently dropped and the model never sees it.Diagnosis
The string is generated by
services/cloud-agent-next/wrapper/src/session-bootstrap.ts(downloadAndMaterializeAttachment): when the wrapper in the sandbox fetches the presigned R2 attachment URL, any fetch/read error is interpolated verbatim into a synthetic text part:text: `attachment ${attachment.filename} could not be retrieved (${message})`So
(undefined is not a function)is a raw JSTypeErrormessage leaking into the user-visible transcript. It matches a known class of Bun Web Streams bugs where reading afetch()response body whose bytes arrive after the response head throws exactlyTypeError: undefined is not a function(see oven-sh/bun#34302, #28952, #28953). I reproduced the exact message 100/100 times on Bun 1.3.12 by iterating a delayed-bodyResponse.body; the failure is intermittent in production and depends on network latency + runtime version.Impact
undefined is not a function) is meaningless to users and agents.Proposed fix
PR (once open): https://github.com/Kilo-Org/cloud/pull/XXXX
response.arrayBuffer()(the workaround the Bun maintainers verified never hits the stream race) whencontent-lengthis bounded.attachment <name> could not be retrieved (download failed after N attempts)and log the raw reason instead of leaking raw JS errors.