shareAI-lab/learn-claude-code · error · GoalError
goal evaluator 'impossible' must be boolean
Error message
goal evaluator 'impossible' must be boolean
What it means
The optional 'impossible' field defaults to false but, when present, must be a real boolean; GoalError("goal evaluator 'impossible' must be boolean") guards against truthy stand-ins like 1, "yes", or null. impossible=true lets the loop terminate a goal that cannot be met, so its type must be exact.
Source
Thrown at s17_goal_loop/code.py:192
lines = stripped.splitlines()
if lines and lines[0].startswith("```"):
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,View on GitHub (pinned to 985456f4ad)
Solutions
- Constrain 'impossible' in the evaluator schema to type:boolean (or omit the field entirely when false).
- Show the allowed literal values in the evaluator prompt example.
- Coerce in a custom evaluator: emit the field only as a JSON true/false literal.
Example fix
# before: {"ok": false, "reason": "blocked", "impossible": "no"}
# after: {"ok": false, "reason": "blocked", "impossible": false} Defensive patterns
Strategy: type-guard
Validate before calling
import json
obj = json.loads(evaluator_text)
imp = obj.get("impossible", False)
assert imp is True or imp is False, "'impossible' must be a JSON boolean when present" Type guard
def impossible_is_bool_or_absent(value: object) -> bool:
if not isinstance(value, dict) or "impossible" not in value:
return True
return isinstance(value["impossible"], bool) Try / catch
try:
ev = _parse_json_object(text)
except GoalError as e:
if "'impossible' must be boolean" in str(e):
obj = json.loads(text)
obj.pop("impossible", None) # drop malformed optional field, default false applies
ev = _parse_json_object(json.dumps(obj))
else:
raise Prevention
- Constrain 'impossible' to type:boolean in the evaluator schema, or tell the model to omit it when false.
- Show the literal true/false values in the prompt example.
- In custom evaluators, never emit yes/no strings for boolean fields.
When it happens
Trigger: Evaluator JSON containing "impossible": "no" / 0 / null / [false] — present but not a bool.
Common situations: Models echoing free-text yes/no values; schemas allowing any type for the field; evaluators copying 'impossible' from prose annotations.
Related errors
- goal evaluator response requires boolean 'ok'
- goal evaluator returned invalid JSON
- goal evaluator must return a JSON object
- goal evaluator response requires non-empty 'reason'
- goal evaluator cannot return both ok and impossible
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/27ed672ab6671cbb.
Report an issue: GitHub.