shareAI-lab/learn-claude-code · error · GoalError
goal evaluator cannot return both ok and impossible
Error message
goal evaluator cannot return both ok and impossible
What it means
The goal evaluator (a separate prompt-based model that judges the transcript) returned a JSON object whose 'ok' field is true while its 'impossible' field is also true. These are contradictory verdicts: 'ok' means the goal is met, 'impossible' means the goal can never be met. The library validates the evaluator's JSON response in _validate (s17_goal_loop/code.py:194) and rejects this combination before it can corrupt goal state.
Source
Thrown at s17_goal_loop/code.py:194
lines = lines[1:]
if lines and lines[-1].strip() == "```":
lines = lines[:-1]
stripped = "\n".join(lines).strip()
try:
value = json.loads(stripped)
except json.JSONDecodeError as error:
raise GoalError("goal evaluator returned invalid JSON") from error
if not isinstance(value, dict):
raise GoalError("goal evaluator must return a JSON object")
if not isinstance(value.get("ok"), bool):
raise GoalError("goal evaluator response requires boolean 'ok'")
if not isinstance(value.get("reason"), str) or not value["reason"].strip():
raise GoalError("goal evaluator response requires non-empty 'reason'")
impossible = value.get("impossible", False)
if not isinstance(impossible, bool):
raise GoalError("goal evaluator 'impossible' must be boolean")
if value["ok"] and impossible:
raise GoalError(
"goal evaluator cannot return both ok and impossible"
)
return {
"ok": value["ok"],
"reason": value["reason"].strip(),
"impossible": impossible,
}
class PromptGoalEvaluator:
"""A separate, tool-free model that judges the transcript."""
def __init__(
self,
client: Any,
model: str,
max_tokens: int = DEFAULT_EVALUATOR_MAX_TOKENS,
):View on GitHub (pinned to 985456f4ad)
Solutions
- Set GOAL_EVALUATOR_MODEL_ID to a stronger model so verdicts are consistent
- Tighten the evaluator system prompt: explicitly state 'never set both ok and impossible; impossible only when ok is false'
- Rephrase the goal condition to be concrete and verifiable so the evaluator is not forced to hedge
- Wrap the session query in try/except GoalError and retry or fall back to manual judgment
Example fix
# before
goal.set_goal("make the app good")
# after
goal.set_goal("all tests in tests/ pass when run with pytest") Defensive patterns
Strategy: retry
Validate before calling
verdict = json.loads(evaluator_output)
if not isinstance(verdict, dict):
raise ValueError("evaluator output is not an object")
if verdict.get("ok") is True and verdict.get("impossible", False) is True:
# contradictory verdict: re-ask the evaluator instead of passing it through
verdict = reask_evaluator(strict_prompt=True) Type guard
def is_consistent_verdict(v: object) -> bool:
return (
isinstance(v, dict)
and isinstance(v.get("ok"), bool)
and isinstance(v.get("impossible", False), bool)
and not (v["ok"] and v["impossible"])
) Try / catch
try:
result = await session.submit(query)
except GoalError as error:
if "cannot return both ok and impossible" in str(error):
result = await session.submit(query) # one retry; verdicts usually converge
else:
raise Prevention
- Pin GOAL_EVALUATOR_MODEL_ID to a capable model rather than the cheapest default
- State in the evaluator prompt that ok and impossible are mutually exclusive
- Keep goal conditions concrete so the evaluator never needs to hedge
When it happens
Trigger: A PromptGoalEvaluator model call returns a response such as {"ok": true, "reason": "done", "impossible": true} — usually from a weak or confused evaluator model, an ambiguous prompt, or output that happens to set both flags. Any session.run()/query cycle that invokes the evaluator can surface it.
Common situations: Using a small/cheap model (e.g. a haiku-tier default from GOAL_EVALUATOR_MODEL_ID or ANTHROPIC_DEFAULT_HAIKU_MODEL) as the evaluator; ambiguous goal conditions the model hedges on; prompt templates for the evaluator that do not forbid setting both flags; JSON produced by the model being partially malformed semantically even though it parses.
Related errors
- goal evaluator returned invalid JSON
- goal evaluator must return a JSON object
- goal evaluator response requires boolean 'ok'
- goal evaluator response requires non-empty 'reason'
- goal evaluator 'impossible' must be boolean
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/62007077d3399730.
Report an issue: GitHub.