{"record":{"id":"8211016082d73cb5","repo":"langchain-ai/deepagents","slug":"must-contain-non-whitespace-text","errorCode":null,"errorMessage":"must contain non-whitespace text","messagePattern":"must contain non-whitespace text","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/goal_rubric.py","lineNumber":212,"sourceCode":"            max_length=RUBRIC_CHAR_LIMIT,\n            description=\"A concise flat Markdown bullet list of acceptance criteria.\",\n        ),\n    ]\n\n    @field_validator(\"objective\", \"criteria\")\n    @classmethod\n    def _require_nonempty_text(cls, value: str) -> str:\n        \"\"\"Reject whitespace-only structured output so the model can retry.\n\n        Returns:\n            The original nonempty text.\n\n        Raises:\n            ValueError: If `value` contains only whitespace.\n        \"\"\"\n        if not value.strip():\n            msg = \"must contain non-whitespace text\"\n            raise ValueError(msg)\n        return value\n\n    @model_validator(mode=\"after\")\n    def _fit_notice_budget(self) -> Self:\n        \"\"\"Reject a proposal whose objective and criteria exceed the budget.\n\n        Returns:\n            The original proposal when it fits.\n\n        Raises:\n            GoalStateSizeError: If the combined text exceeds the notice budget.\n                pydantic wraps a `ValueError` raised inside a `model_validator`,\n                so a caller constructing a `GoalProposal` directly observes a\n                `ValidationError` carrying this message, never this type. Inside\n                an agent, `_raise_terminal_goal_state_size_error` unwraps it back\n                to this type and ends the turn rather than retrying, because the\n                combined budget is deterministic and half of it is the user's\n                objective. The direct `validate_goal_application` calls raise it","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/goal_rubric.py#L194-L230","documentation":"`_require_nonempty_text` is a Pydantic validator for goal-rubric fields that rejects values consisting only of whitespace, raising `ValueError('must contain non-whitespace text')`. Goal proposals (objective/criteria text) must carry real content so the rubric evaluator receives meaningful text.","triggerScenarios":"Constructing or validating a goal-rubric model with a field set to `''`, `'   '`, `'\\n\\t'`, or a value stripped to empty — e.g. an LLM produced an empty objective string that was passed straight into the model.","commonSituations":"Model outputs truncated to whitespace; templates with unfilled placeholders that collapse to empty; upstream code doing `.get(\"objective\", \"\")` defaulting to empty string; whitespace-only joins of criteria lists.","solutions":["Ensure the field value is trimmed, non-empty text before constructing the model","Check the upstream producer (e.g. LLM response) and re-prompt or fail fast when it returns empty/whitespace text","Handle the `ValueError` at the boundary and surface which field was empty"],"exampleFix":"// before\nrubric = GoalRubric(objective=\"   \", criteria=[\"tests pass\"])\n\n// after\nobjective = raw_objective.strip()\nif not objective:\n    raise ValueError(\"objective must contain non-whitespace text\")\nrubric = GoalRubric(objective=objective, criteria=[\"tests pass\"])","handlingStrategy":"validation","validationCode":"def ensure_text(v: str, field: str) -> str:\n    v = (v or \"\").strip()\n    if not v:\n        raise ValueError(f\"{field} must contain non-whitespace text\")\n    return v","typeGuard":"def is_nonempty_text(v: object) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":"try:\n    rubric = GoalRubric(objective=raw, criteria=items)\nexcept ValueError as exc:\n    logger.error(\"invalid goal text: %s\", exc)","preventionTips":["Strip and check LLM-produced fields before model construction","Fail fast at the producer boundary when responses are empty","Default to re-prompting instead of passing empty strings downstream"],"tags":["validation","pydantic","goal-rubric"],"backgroundTag":"empty-required-field","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}