shareAI-lab/learn-claude-code · error · GoalError
background result cannot be empty
Error message
background result cannot be empty
What it means
AgentSession.submit_background_result was called with text that is empty after stripping (s17_goal_loop/code.py:653). This method resumes the loop by appending a '[Background task completed]' user message carrying the background output; an empty body would resume the agent with no new information, so it is rejected.
Source
Thrown at s17_goal_loop/code.py:653
def _summary_hook(messages: list[dict[str, Any]]) -> None:
tool_count = sum(
1
for message in messages
for block in (
message.get("content")
if isinstance(message.get("content"), list)
else []
)
if isinstance(block, dict) and block.get("type") == "tool_result"
)
print(f"[hook] Stop: session used {tool_count} tool calls")
return None
async def submit_background_result(self, text: str) -> SessionResult:
"""Resume an active goal after the host receives background output."""
if not text.strip():
raise GoalError("background result cannot be empty")
self.messages.append(
{
"role": "user",
"content": f"[Background task completed]\n{text}",
}
)
if self.goal.active is None:
return SessionResult(text="", status="background_result")
self.goal.begin_query()
return await self._run_query()
async def _run_query(self) -> SessionResult:
turns = 0
while True:
if self.max_turns is not None and turns >= self.max_turns:
self.trigger_hooks("Stop", self.messages)
return SessionResult(
text="",View on GitHub (pinned to 985456f4ad)
Solutions
- Capture and check output before submitting; if empty, surface stderr or the exit code to the agent in the text
- Include the exit status in the text so it is never blank: f'exit={rc}\n{stdout}'
- If the background task genuinely produced nothing, submit a meaningful sentinel like '(no output, exit 0)' instead of an empty string
Example fix
# before
await session.submit_background_result(proc.stdout)
# after
stdout, stderr = proc.communicate()
text = stdout.strip() or stderr.strip() or f"(no output; exit {proc.returncode})"
await session.submit_background_result(text) Defensive patterns
Strategy: validation
Validate before calling
text = (stdout or "").strip()
if not text:
text = (stderr or "").strip() or f"(no output; exit {returncode})"
await session.submit_background_result(text) Type guard
def is_submittable_background_result(text: object) -> bool:
return isinstance(text, str) and bool(text.strip()) Try / catch
try:
await session.submit_background_result(text)
except GoalError:
text = "(background task produced no output)"
await session.submit_background_result(text) Prevention
- Always compose the payload with exit status so it can never be blank
- Submit stderr when stdout is empty; failing commands log there
- Guard the resume call at the host boundary rather than letting whitespace through
When it happens
Trigger: Calling submit_background_result("") or submit_background_result(" \n "); forwarding a background process's stdout that was empty or only whitespace; calling it before the background task produced output.
Common situations: Host process wakes on a background-job-exit event and forwards captured stdout without checking it; background command failed with output on stderr only; race where the result is submitted before the writer flushed.
Related errors
- Only Bash commands can run in the background
- Bash command cannot be empty
- goal evaluator must return a JSON object
- goal evaluator response requires non-empty 'reason'
- block_cap must be at least 1
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/444d7a925478e416.
Report an issue: GitHub.