langgenius/dify · error · Error

streaming response body missing

Error message

streaming response body missing

What it means

Raised by DatasetsHitTestingBase._prepare_hit_testing_records when an individual element of the records list returned by HitTestingService.retrieve is not a dict. This is a defensive contract check that the retrieval service produced the expected record shape before response serialization. It is an internal/server-side failure, not caused by user input, and surfaces as a ValueError (HTTP 500 after the broad except in perform_hit_testing re-raises it).

Source

Thrown at cli/src/api/app-run.ts:62

    // `http.stream` facade; stopTask / submitHumanInput are plain JSON and go through the
    // generated oRPC contract. Both facades share this one transport.
    this.orpc = createOpenApiClient(http)
  }

  async runStream(
    appId: string,
    body: Record<string, unknown>,
    opts: StreamOptions = {},
  ): Promise<AsyncIterable<SseEvent>> {
    const res = await this.http.stream(`apps/${encodeURIComponent(appId)}:run`, {
      method: 'POST',
      json: body,
      headers: { Accept: 'text/event-stream' },
      signal: opts.signal,
      throwOnError: true,
      retryOnRateLimit: opts.retryOnRateLimit,
    })
    if (res.body === null) throw new Error('streaming response body missing')
    return normalizeDifyStream(parseSSE(res.body, opts.signal))
  }

  async stopTask(appId: string, taskId: string): Promise<void> {
    await this.orpc.apps.byAppId.tasks.byTaskId.stop.post({
      params: { app_id: appId, task_id: taskId },
    })
  }

  async submitHumanInput(
    appId: string,
    formToken: string,
    action: string,
    inputs: Record<string, unknown>,
  ): Promise<void> {
    await this.orpc.apps.byAppId.humanInputForms.byFormToken.submit.post({
      params: { app_id: appId, form_token: formToken },
      body: { action, inputs },

View on GitHub (pinned to ef8544b173)

Solutions

  1. Inspect server logs for the full stack trace to identify which record and retrieval backend produced the non-dict value.
  2. Ensure any custom/external retrieval implementation returns records as plain dicts (call model_dump(mode='json') on ORM/pydantic objects before returning).
  3. Add a unit test against HitTestingService.retrieve output asserting every record is a dict with the expected keys.

Example fix

# before (retrieval service)
return {"query": q, "records": [some_segment_model, ...]}
# after
return {"query": q, "records": [s.model_dump(mode='json') if hasattr(s, 'model_dump') else s for s in segments]}
Defensive patterns

Strategy: try-catch

Validate before calling

from typing import Any

def is_valid_records_payload(response: Any) -> bool:
    return (
        isinstance(response, dict)
        and isinstance(response.get('records'), list)
        and all(isinstance(r, dict) for r in response['records'])
    )
# in retrieval service: assert is_valid_records_payload(result) before returning

Type guard

from typing import Any

def is_hit_testing_record(value: Any) -> bool:
    return isinstance(value, dict)

Try / catch

try:
    return DatasetsHitTestingBase._prepare_hit_testing_records(response.get('records', []))
except ValueError:
    logger.exception('retrieve returned malformed records: %r', response.get('records'))
    raise  # surfaces as 500; this is a server-side contract bug, not retryable

Prevention

When it happens

Trigger: HitTestingService.retrieve returns a list whose element is None, a string, or a pydantic model that was not dumped to a dict. Typically the result of a custom retrieval backend, a malformed external knowledge adapter, or a regression in the retrieve service after a schema change.

Common situations: A plugin/external knowledge endpoint returns a non-object record; an in-development retrieval adapter forgets to call .model_dump() on segment objects; version skew between the retrieval service and the controller normalization layer.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/4c11db670a970ef0. Report an issue: GitHub.