datawhalechina/hello-agents · error

stream request failed: ${resp.status} ${message}

Error message

stream request failed: ${resp.status} ${message}

What it means

Streaming-report client: POSTs {question, start_date, end_date, site_id} to a report endpoint and requires both resp.ok AND resp.body; on failure it reads the body text and throws 'stream request failed: <status> <body>'. It then reads agent metadata from X-Agent-* response headers, so any interceptor that strips headers also breaks features downstream — but the throw itself is the HTTP/stream failure.

Source

Thrown at Co-creation-projects/monkeyhlj-NetworkHealthReportAgent/frontend/src/api.js:100

export async function askQuestionStream(question, startDate, endDate, siteId = null, onChunk) {
  const base = await resolveBase()
  const resp = await fetch(`${base}/chat/stream`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      question,
      start_date: startDate,
      end_date: endDate,
      site_id: siteId
    })
  })

  if (!resp.ok || !resp.body) {
    const message = await resp.text()
    throw new Error(`stream request failed: ${resp.status} ${message}`)
  }

  const meta = {
    llmEnabled: resp.headers.get('X-Agent-LLM') === 'true',
    mcpEnabled: resp.headers.get('X-Agent-MCP') === 'true',
    reportIntent: resp.headers.get('X-Agent-Report-Intent') === 'true',
    artifactUrl: resp.headers.get('X-Agent-Artifact-Url') || '',
    artifactName: resp.headers.get('X-Agent-Artifact-Name') || ''
  }

  const reader = resp.body.getReader()
  const decoder = new TextDecoder('utf-8')

  while (true) {
    const { done, value } = await reader.read()
    if (done) {
      break
    }

View on GitHub (pinned to 606a07d341)

Solutions

  1. curl -N -i the endpoint with the exact payload to see status/body and whether the stream opens
  2. If 502/504, raise proxy_read_timeout / proxy_buffering off for the stream route
  3. If 422, validate start_date/end_date format and site_id against the backend schema before sending
  4. Split the combined check: handle !resp.ok (HTTP error, read body) separately from !resp.body (no stream), and set Access-Control-Expose-Headers for X-Agent-*

Example fix

// before
if (!resp.ok || !resp.body) {
    const message = await resp.text()
    throw new Error(`stream request failed: ${resp.status} ${message}`)
}

// after
if (!resp.ok) {
    const message = await resp.text().catch(() => '')
    throw new Error(`stream request failed: ${resp.status} ${message.slice(0, 200)}`)
}
if (!resp.body) {
    throw new Error('stream unavailable: response has no body')
}
Defensive patterns

Strategy: validation

Validate before calling

if (!question.trim()) throw new Error('question required'); if (!/^\d{4}-\d{2}-\d{2}$/.test(startDate) || !/^\d{4}-\d{2}-\d{2}$/.test(endDate) || startDate > endDate) throw new Error('invalid date range');

Type guard

function isStreamOk(resp) { return resp.ok && !!resp.body && typeof resp.body.getReader === 'function'; }

Try / catch

try { const resp = await fetch(url, opts); if (!resp.ok) throw new Error(`stream request failed: ${resp.status}`); if (!resp.body) throw new Error('no stream body'); } catch (e) { fallbackToPollingReport(); }

Prevention

When it happens

Trigger: 422 from bad/missing date range or site_id; 404 when the stream route isn't deployed; 500 from the report agent; 502/504 from a proxy that times out the long-lived stream; a body-less HTTP/204 response (fails the !resp.body clause even though ok).

Common situations: Reverse proxy (nginx default 60s proxy_read_timeout) cutting off long report generation; site_id not matching the network inventory; env-based base URL (same candidate probing as error 18) resolving to a host without the stream route; CORS not exposing X-Agent-* headers (needs Access-Control-Expose-Headers).

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/7454ec5ced379781. Report an issue: GitHub.