iflytek/astron-agent · error · CustomException

SPARK_REQUEST_ERROR

SPARK_REQUEST_ERROR

Error message

LLM returned empty result

What it means

Thrown by the workflow engine's LLM streaming consumer (_consume_llm_stream, called from _chat_with_llm) when the model stream ends without yielding any text chunks. The engine treats an empty completion as a provider/model failure rather than a valid empty answer, tags the span with 'result is null', and raises SPARK_REQUEST_ERROR so the node fails visibly instead of returning an empty string downstream.

Solutions

  1. Check the span error event 'result is null' and the upstream provider logs to confirm whether the stream contained any chunks at all.
  2. Retry the request; if intermittent, add retry with backoff around the LLM call in _chat_with_llm.
  3. Verify model configuration: max_tokens, temperature, and that the selected model actually produces content (not reasoning-only) for this prompt.
  4. Validate the API key/endpoint and that content filters are not suppressing output; test the same prompt against the provider directly.
  5. If the model legitimately returns empty output, handle it upstream (e.g. add a fallback prompt or allow empty results) before it reaches this check.

Example fix

// before: empty stream bubbles up as SPARK_REQUEST_ERROR
result = await node._chat_with_llm(prompt)

// after: validate/retry before consuming
for attempt in range(3):
    try:
        result = await node._chat_with_llm(prompt)
        if result.strip():
            break
    except CustomException:
        if attempt == 2: raise
        await asyncio.sleep(2 ** attempt)
Defensive patterns

Strategy: retry

Validate before calling

def has_text(stream_result):
    return bool(stream_result and stream_result.strip())

Type guard

def is_nonempty_str(v) -> bool:
    return isinstance(v, str) and len(v.strip()) > 0

Try / catch

try:
    token_usage, text, reasoning, status = await node._chat_with_llm(prompt)
except CustomException as e:
    if e.err_code == CodeEnum.SPARK_REQUEST_ERROR:
        log.warning("empty LLM result, retrying")
        text = await retry_with_backoff(lambda: node._chat_with_llm(prompt))
    else:
        raise

Prevention

When it happens

Trigger: The LLM stream finishes (normal or unexpected stop status) while the accumulated `texts` list is empty — e.g. the model returned only reasoning content, the provider sent zero content deltas, a content filter stripped the output, or the stream was cut before any chunk arrived.

Common situations: Misconfigured model endpoint returning 200 with an empty body; max_tokens set too low so the model emits nothing; prompt triggers a safety refusal that suppresses content; reasoning-only models whose text field is empty; transient provider outages; wrong API key causing a silently empty stream wrapper.

Understand the failure class

Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/108a6ad6905d31ee. Report an issue: GitHub.

Appendix: source

Thrown at core/workflow/engine/nodes/base_node.py:1334

                await self.put_llm_content(
                    node_id=self.node_id,
                    model_name=self.domain,
                    variable_pool=request.variable_pool,
                    msg_or_end_node_deps=request.msg_or_end_node_deps,
                    llm_content=msg,
                )
            texts.append(content or "")
            if status in {
                SparkLLMStatus.END.value,
                ChatStatus.FINISH_REASON.value,
            }:
                break
            if self._is_unexpected_finish_status(status):
                raise CustomException(err_code=CodeEnum.OPEN_AI_REQUEST_ERROR)

        if not texts:
            request.span.add_error_event("result is null")
            raise CustomException(
                err_code=CodeEnum.SPARK_REQUEST_ERROR,
                err_msg="LLM returned empty result",
                cause_error="LLM returned empty result",
            )
        return token_usage, "".join(texts), "".join(reasoning_contents), status

    async def _finish_generation_span(
        self,
        span: Span,
        answer: str,
        reasoning: str,
        token_usage: dict,
        status: Any,
    ) -> None:
        await span.add_info_events_async({"spark_llm_chat_result": answer})
        await span.add_info_events_async({"spark_llm_reasoning_content": reasoning})
        result_attributes = langfuse_observation_attributes(
            "generation",

View on GitHub (pinned to 5e758547a8)