{"record":{"id":"da28adbece97f985","repo":"langchain-ai/deepagents","slug":"goal-criteria-request-must-be-an-object","errorCode":null,"errorMessage":"Goal criteria request must be an object.","messagePattern":"Goal criteria request must be an object\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/goal_rubric.py","lineNumber":1214,"sourceCode":"        summary = summary[:_CRITERIA_RESULT_LOG_LIMIT] + \"...\"\n    return summary\n\n\ndef _goal_criteria_request(value: object) -> GoalCriteriaRequest:\n    \"\"\"Validate a goal-criteria request from graph input.\n\n    Returns:\n        A normalized typed request: a `GoalAmendRequest` when `kind` is amend\n        (with `criteria` and `feedback` guaranteed present), otherwise a\n        `GoalCreateRequest`. Fields not valid for the resolved kind are dropped.\n\n    Raises:\n        TypeError: If the request or one of its fields has the wrong type.\n        ValueError: If a required request value is missing or invalid.\n    \"\"\"\n    if not isinstance(value, dict):\n        msg = \"Goal criteria request must be an object.\"\n        raise TypeError(msg)\n    request_id = value.get(\"request_id\")\n    kind = value.get(\"kind\")\n    objective = value.get(\"objective\")\n    if not isinstance(request_id, str) or not request_id.strip():\n        msg = \"Goal criteria request requires a request_id.\"\n        raise ValueError(msg)\n    if kind not in {\"create\", \"amend\"}:\n        msg = \"Goal criteria request kind must be create or amend.\"\n        raise ValueError(msg)\n    if not isinstance(objective, str) or not objective.strip():\n        msg = \"Goal criteria request requires an objective.\"\n        raise ValueError(msg)\n\n    # Values are validated for non-blankness but stored verbatim (not stripped):\n    # this feature deliberately preserves the user's exact goal/criteria wording,\n    # and the prompt builders wrap each value in explicit XML boundaries.\n    optional: dict[str, str] = {}\n    for key in (\"criteria\", \"feedback\", \"previous_criteria\"):","sourceCodeStart":1196,"sourceCodeEnd":1232,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/goal_rubric.py#L1196-L1232","documentation":"`_goal_criteria_request` (a hook used by `before_agent`/`abefore_agent`) parses an incoming goal-criteria request payload and raises `TypeError` if the payload is not a `dict`. It then further validates `request_id`, `kind`, and `objective`, raising `ValueError` for missing/invalid required fields. This guards the tool/hook boundary against malformed requests.","triggerScenarios":"A before-agent hook receives a request value that is a JSON string, list, or None instead of an object — e.g. the client sent `\"{...}\"` as a string, an array of fields, or omitted the payload entirely.","commonSituations":"Tool clients double-encoding JSON so the object arrives as a string; schema drift between caller and hook (field renamed/moved); programmatic callers passing the wrong structure; agent state containing a list of requests instead of a single request object.","solutions":["Send the request as a JSON object with string `request_id`, valid `kind`, and non-empty `objective`","If receiving a JSON string, `json.loads` it before handing it to the hook","Validate the payload shape at the client boundary before invoking the agent"],"exampleFix":"// before\nawait hook.before_agent(state, request='{\"request_id\": \"r1\", ...}')\n\n// after\nimport json\npayload = request if isinstance(request, dict) else json.loads(request)\nawait hook.before_agent(state, payload)","handlingStrategy":"type-guard","validationCode":"def validate_request(value) -> dict:\n    if not isinstance(value, dict):\n        raise TypeError(\"Goal criteria request must be an object.\")\n    if not isinstance(value.get(\"request_id\"), str) or not value[\"request_id\"].strip():\n        raise ValueError(\"request_id required\")\n    return value","typeGuard":"def is_criteria_request(v: object) -> bool:\n    return (\n        isinstance(v, dict)\n        and isinstance(v.get(\"request_id\"), str)\n        and bool(v[\"request_id\"].strip())\n        and isinstance(v.get(\"objective\"), str)\n        and bool(v[\"objective\"].strip())\n    )","tryCatchPattern":"try:\n    validated = _goal_criteria_request(payload)\nexcept TypeError as exc:\n    logger.error(\"payload not an object: %s\", exc)\nexcept ValueError as exc:\n    logger.error(\"invalid request field: %s\", exc)","preventionTips":["json.loads string payloads before passing them to hooks","Keep client and hook request schemas in sync; validate at the boundary","Never pass None or lists where an object is expected"],"tags":["validation","type-error","agent-hooks"],"backgroundTag":"invalid-request-payload","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}