tinyhumansai/openhuman · error · AgentError::EmptyProviderResponse
The model returned an empty response. Please try again.
Error message
The model returned an empty response. Please try again.
What it means
End-of-turn guard in the agent harness: the model reply contained no text and no tool calls. The trailing empty assistant row is popped from history first (so strict providers like Anthropic don't 400 the next request on an empty content block), then this user-facing retry prompt is returned.
Source
Thrown at src/openhuman/agent/harness/session/turn/core.rs:1434
// branch below pops that dangling blank row before re-prompting, but
// this `tool_calls == 0` path returned the error with the empty row
// still in history — so the *next* request carried an empty-content
// assistant message and strict providers (Anthropic: "text content
// blocks must be non-empty") 400 the whole thread, not just this turn.
// Pop the trailing empty assistant row before returning so a retry
// sends a clean transcript.
if matches!(
self.history.last(),
Some(ConversationMessage::Chat(msg))
if msg.role == "assistant" && msg.content.trim().is_empty()
) {
log::debug!(
"[agent_loop] EmptyProviderResponse at iteration {}: popping dangling empty assistant row before returning — #4457 defect A",
outcome.model_calls
);
self.history.pop();
}
return Err(anyhow::Error::new(
crate::openhuman::agent::error::AgentError::EmptyProviderResponse {
iteration: outcome.model_calls,
},
));
} else if outcome.text.trim().is_empty() {
// #4093: the loop ran tool calls (tool_calls > 0, so the branch
// above did not fire) and then yielded a terminating response with
// no final text — the turn did work but would otherwise end
// silently, leaving the user with nothing. Enforce the
// "must produce a final response" terminal step: re-prompt the
// model (tools disabled) for a closing summary of what it did,
// falling back to a deterministic summary of the tool calls so the
// synthesized message is never itself empty. Fold the extra call's
// usage into the turn accounting, exactly like the cap path above.
let base = self.tool_dispatcher.to_provider_messages(&self.history);
let (summary, summary_usage) = self
.summarize_turn_wrapup(
&base,View on GitHub (pinned to 7491200858)
Solutions
- Retry the turn — the transcript is clean, so a re-prompt usually gets a real reply
- If recurring, check provider health/model availability for degraded empty completions
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at src/openhuman/agent/harness/session/turn/core.rs:1434 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/f2eb67c745452158.
Report an issue: GitHub.