langchain-ai/deepagents · error · ValueError
goal application requires a non-empty objective and rubric
Error message
goal application requires a non-empty objective and rubric
What it means
A goal application (objective + rubric pair) was constructed with an empty `objective` or `rubric`. The dataclass `__post_init__` enforces that both fields are non-empty before delegating to `validate_goal_application` for size limits, failing fast on structurally useless goal definitions.
Source
Thrown at libs/code/deepagents_code/app.py:2349
def __post_init__(self) -> None:
"""Reject an empty or oversized objective or rubric at construction.
Callers already screen these (`_accept_goal_rubric`), so this guards
against a future construction site skipping that check — queuing a goal
that would clear the active one to nothing, or one whose text cannot
render as a goal-state notice. Holding both invariants here means they
do not depend on every construction site remembering; callers keep their
own checks so they can report a targeted message before mutating UI
state.
Raises:
ValueError: If `objective` or `rubric` is empty.
GoalStateSizeError: If either exceeds its own limit, or their
combined text exceeds `GOAL_APPLICATION_CHAR_LIMIT`.
""" # noqa: DOC502 - propagates from `validate_goal_application`
if not self.objective or not self.rubric:
msg = "goal application requires a non-empty objective and rubric"
raise ValueError(msg)
validate_goal_application(self.objective, self.rubric)
@dataclass(frozen=True, slots=True)
class _GoalApplicationResult:
"""Applied goal transition and whether its checkpoint write succeeded."""
transition: Literal["create", "amended"]
persisted: bool
@dataclass(frozen=True, slots=True)
class _BlockedGoalResetResult:
"""Blocked-goal reset outcome used to gate the following user turn.
Build instances through `proceed`, `reset`, or `failed` so only valid
field combinations are constructed. `did_reset` — not a `blocker_note`
sentinel — is the authoritative signal that a blocked goal was flippedView on GitHub (pinned to a1af029e6e)
Solutions
- Supply a non-empty objective and a non-empty rubric before constructing the object
- Strip whitespace and reject empty strings at the input boundary
- If a goal is genuinely absent, skip construction instead of passing empty strings
Example fix
// before
GoalApplication(objective="", rubric="answer correctly")
// after
if not objective.strip() or not rubric.strip():
raise ValueError("objective and rubric are required")
GoalApplication(objective=objective, rubric=rubric) Defensive patterns
Strategy: validation
Validate before calling
if not objective or not objective.strip() or not rubric or not rubric.strip():
raise ValueError("goal application requires a non-empty objective and rubric") Type guard
def has_goal_fields(goal: object) -> bool:
return (
isinstance(goal, GoalApplication)
and bool(goal.objective)
and bool(goal.rubric)
) Try / catch
try:
goal = GoalApplication(objective=obj, rubric=rub)
except ValueError as exc:
logger.warning("invalid goal: %s", exc)
return None Prevention
- Strip and check text fields at the input/UI boundary
- Treat whitespace-only strings as empty
- Skip goal construction entirely when a field is genuinely absent
- Test config-loading paths with blank template fields
When it happens
Trigger: Constructing the goal-application dataclass with `objective=''`, `rubric=''`, or None — typically from empty form fields, a config file with blank keys, or a programmatic call that passed unvalidated user input.
Common situations: Automation that builds goals from config/templates where a placeholder was never filled; user submitted a goal form with one field blank.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- shell_allow_list must be None or non-empty
- RewarmEstimate costs must be finite, got cold={self.cold_cos
- RewarmEstimate costs must be non-negative, got cold={self.co
- RewarmEstimate incremental cost {self.incremental_cost_usd!r
- ColdCacheWarning age_seconds={self.age_seconds!r} does not p
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/0f272f33b02bf668.
Report an issue: GitHub.