deepseek messages transport failed vs stream cut-off
Failing in 20 milliseconds and dying after 20 seconds are two different diseases; calling both transport failed means taking the wrong medicine. In DeepSeek Harness, DeepSeek Messages transport failed (code: TRANSPORT) is a transport-layer catch-all: any failure not classified as an idle timeout, a deliberate cancel or an existing LlmError gets wrapped in it (source). The real question is therefore not "why TRANSPORT" but "how far did this request get". This article follows a triage path rather than re-explaining the catch-all itself.
Reading the code first: what TRANSPORT, timeout and 401/400 mean in DeepSeek Harness
The error code sets the direction: TRANSPORT is unclassified, TIMEOUT means no new chunk for too long, and 401/400 is a business or credential rejection. Match the code before deciding whether to retry.
| Code in the log | Meaning | Layer | Retry? |
|---|---|---|---|
TRANSPORT | Unclassified transport failure | Request prep / connection / streaming | Usually yes, but read cause first |
TIMEOUT | Idle watchdog expired | Streaming stage | Yes |
ABORTED | Request deliberately cancelled | User action | No |
| 401 / 400 and similar | LlmError with its own code | Credentials / parameters / quota | Depends on the code |
- Find the
turn/endrecord for this round in the log and confirm the outer code. - If the outer code is
TRANSPORT, expandcauseand read the original code inside. - If the outer code is
TIMEOUTorABORTED, stop debugging it as transport. - If the outer code is 401 or 400, inspect credentials and request parameters instead of the network.
- Record both the code and its cause; do not copy only the message text.
The code is the entrance to triage, not the conclusion. TRANSPORT only says "could not classify"; the cause below it carries identity. A 401 or 400 should not look like transport failed in the first place, and if it does, the request was stopped before reaching the application layer.
Three signs of stream cut-off: DSH plugin changes count as variables
A cut-off stream looks like "some content arrived, then it froze", not "nothing happened at all". When the three signs appear together, the direction is almost certainly connection or proxy.
- Content streams for a while, stops midway, and never ends cleanly.
- The request status is 200, but the stream never finishes and the client waits for a final frame that never comes.
- Logs show streaming events first, followed by a connection error or retry record.
Environment changes count too: a new proxy, a packet capture tool, a plugin upgrade or a network change can all start a cut-off. The plugin itself is not necessarily wrong, but it changed the request path, so do not look only at the model side. For an adjacent TLS re-signing issue, see antivirus TLS certificate chain errors.
Five-minute triage: DeepSeek Harness separates "never sent" from "died halfway"
Five minutes is enough for one triage pass: minutes 0–1 read the code, 1–2 check the request count, 2–3 the endpoint response, and 3–5 the cause before deciding. The order is fixed so you do not swap networks first.
# 1) Is a local proxy intercepting?
env | grep -i -E 'https?_proxy|no_proxy'
# 2) Hit the model endpoint directly for connection and status (replace with your provider base URL)
curl -sS -o /dev/null \
-w 'HTTP %{http_code} connect %{time_connect}s total %{time_total}s\n' \
https://api.deepseek.com/v1/models
- 0–1 minute: confirm the outer code is TRANSPORT, TIMEOUT or 401/400.
- 1–2 minutes: check whether this request was sent at all; a count of zero means local preparation.
- 2–3 minutes: read the endpoint response code; 200 means reachable, 401/403 means rejected.
- 3–4 minutes: read cause and the last streaming event to locate the break point.
- 4–5 minutes: decide retry, resume or fix the environment; decide once instead of experimenting repeatedly.
"Was the request sent" is the highest-information test. A request count of zero with failure in tens of milliseconds usually means local preparation failed; a request that was sent and broke halfway means the connection layer. The fixes are completely different.
Ask one question before retrying
Is this failure deterministic or intermittent?
- It fails at the same point every time: deterministic, fix it before retrying.
- It works at another time: intermittent, record the timestamp and watch.
- It fails only on a specific network or proxy: environment-specific, verify on another path first.
Evidence checklist: five things to copy from DeepSeek Harness logs
Collect five items: time, code and cause, request count, endpoint response code and the last streaming event; add one environment change. With all five, the problem usually lands on a layer.
- The timestamp to the minute, for aligning with other logs.
- The outer code and the original code inside cause; record both.
- Whether the request was sent and the order of magnitude of the failure latency.
- The most recent endpoint response code.
- The last streaming event and whether retry records followed it.
The sixth item is the environment change: proxy, capture tool, plugin additions or removals, version updates. It does not explain the error directly but explains why today. After collecting evidence, decide whether to rerun, resume or file an issue; the session itself does not disappear because one round failed.
Telling it apart from neighbors: when it is not a DeepSeek Harness transport problem
Three cases should not be debugged as transport: credentials or parameters rejected, the front end unable to reach the host, and a missing attachment object. Their codes and scene signatures differ from a cut-off stream.
- 401 / 400 class: these are
LlmErrorwith their own codes; check the key, model name and request parameters. - Front end cannot reach the host: this is the channel between browser and DeepSeek Harness, not a model request.
- Missing attachment: request count is zero, failure takes tens of milliseconds, and every request in that session fails; this is a local preparation problem.
- Plugin-induced environment change: roll back the most recent plugin change and reproduce before looking for model-side causes.
- Same string, different cause: a missing attachment and TLS re-signing can both land on the same message; separate them with "was the request sent".
The point of distinguishing is not tidy categories but a justified next action. For the full mechanics of the transport catch-all, see transport failed troubleshooting; for the attachment-specific scene, see transport failed caused by a missing attachment.
FAQ
DeepSeek Harness uses TRANSPORT as a transport-layer catch-all meaning the failure could not be classified, so it may happen during request preparation, connection setup or streaming. A cut-off stream is one possible scene, not the whole category. To decide whether it was a cut-off, check whether the request was sent and whether partial content arrived.
DeepSeek Harness uses TRANSPORT for an unclassified transport-layer failure, idle timeout maps to TIMEOUT, and 401 or 400 usually arrives as an LlmError with its own code. The first two require reading the cause and the request stage, while the last two are business or credential rejections with a completely different direction.
DeepSeek Harness usually shows three signs of stream cut-off: content arrives and then suddenly stops, the request returns 200 but the stream never finishes cleanly, and logs show streaming events followed by a connection error. When all three appear together, the cause is almost certainly connection or proxy rather than a model rejection.
DeepSeek Harness should first show whether the request was sent: a request count of zero and a failure in tens of milliseconds means local preparation, while a request that was sent and failed halfway means transport interruption. This test is faster than repeated retries and cheaper than swapping networks first.
DeepSeek Harness needs at least five items: the timestamp, the outer error code and cause, the request count, the endpoint response code, and the last streaming event. Add one environment-change note, such as a recent proxy, plugin or version change. With all five, the problem usually lands on a specific layer.
Related Terms
- TRANSPORT
- TRANSPORT is the DeepSeek Harness transport-layer catch-all error code thrown by the llm-deepseek adapter's catch-all, with the message DeepSeek Messages transport failed. It means the failure could not be classified, and the real reason lives in cause.— https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm-deepseek/src/adapter.ts
- stream cut-off
- Stream cut-off is the phenomenon where a model response has begun streaming but the connection breaks before it finishes, leaving content half-delivered and the stream without a clean end. It is not the same as a local preparation failure where the request never left.— https://github.com/deepseek-ai/deepseek-harness
- cause (error chain)
- cause is the original error object preserved when LlmError is wrapped by the catch-all, and the real error code hides in its code field. When debugging TRANSPORT, read cause first instead of trusting the outer message.— https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm-deepseek/src/adapter.ts
- idleWatchdog
- idleWatchdog is the idle watchdog used during DeepSeek Harness streaming requests, firing TIMEOUT when no new chunk arrives within streamIdleTimeoutMs. It is a different classification from TRANSPORT.— https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm-deepseek/src/adapter.ts
Sources
- DeepSeek Harness source - llm-deepseek/src/adapter.ts (TRANSPORT throw site)· deepseek-ai
- DeepSeek Harness official docs - configuring model providers· deepseek-harness
- #7834 - after deleting an attachment object every request fails, misreported as transport failed· deepseek-ai (GitHub Discussions)