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
- Check the span error event 'result is null' and the upstream provider logs to confirm whether the stream contained any chunks at all.
- Retry the request; if intermittent, add retry with backoff around the LLM call in _chat_with_llm.
- Verify model configuration: max_tokens, temperature, and that the selected model actually produces content (not reasoning-only) for this prompt.
- Validate the API key/endpoint and that content filters are not suppressing output; test the same prompt against the provider directly.
- 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
- Set max_tokens high enough that the model always emits content
- Test prompts against the provider directly to detect refilters/empty outputs
- Add retry-with-backoff around LLM calls for transient provider failures
- Monitor spans for 'result is null' events to catch systematic empty responses
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
- (large model request failure)
- Node has no ref node info
- OPEN_AI_REQUEST_ERROR
- UPDATE_BOT_FAILED
- BOT_CHAIN_SUBMIT_ERROR
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)