srbhr/Resume-Matcher · error · ValueError
'original' may be a list only for the reorder action
Error message
'original' may be a list only for the reorder action
What it means
ResumeChange is a Pydantic model representing one LLM-proposed resume edit. Its model validator _list_original_only_for_reorder rejects a list-valued 'original' field when action is anything other than 'reorder', because a list original for text actions would silently bypass the replace verification gate and break the invented-metrics check. The error is raised at parse/validation time with this exact message.
Source
Thrown at apps/backend/app/schemas/models.py:919
)
action: Literal["replace", "append", "reorder", "add_skill"]
original: str | list[str] | None = Field(
default=None,
description="Current text at path — for verification. May be a list (the "
"current items) for the reorder action; only used for text verification of "
"replace/append, ignored otherwise.",
)
value: str | list[str] = Field(description="New content")
reason: str = Field(description="Why this change helps match the JD")
@model_validator(mode="after")
def _list_original_only_for_reorder(self) -> "ResumeChange":
"""A list ``original`` is only meaningful for ``reorder`` (the LLM sends
the current items). For the text actions it must stay a string/None — a
list there would silently bypass the replace verification gate and crash
the invented-metrics check, so reject it at parse time."""
if isinstance(self.original, list) and self.action != "reorder":
raise ValueError("'original' may be a list only for the reorder action")
return self
class ImproveDiffResult(BaseModel):
"""LLM output: a list of targeted resume changes."""
changes: list[ResumeChange] = Field(default_factory=list)
strategy_notes: str = Field(default="")
View on GitHub (pinned to 116f9cc3b0)
Solutions
- Check the action field of the failing ResumeChange; only 'reorder' accepts a list original
- If the change is a text edit, convert original to a string (or null) before constructing the model
- If items must be passed as a list, change action to 'reorder'
- Tighten the LLM prompt/examples so list originals are only emitted for reorder
Example fix
// before ResumeChange(action="replace", original=["old text"], replacement="new text") // after ResumeChange(action="replace", original="old text", replacement="new text")
Defensive patterns
Strategy: validation
Validate before calling
def is_valid_change(c: dict) -> bool:
return isinstance(c.get("original"), list) == (c.get("action") == "reorder") Type guard
def has_list_original(c: ResumeChange) -> bool:
return isinstance(c.original, list) Try / catch
try:
change = ResumeChange.model_validate(raw)
except ValidationError as e:
logger.warning("dropping invalid change: %s", e)
change = None Prevention
- Only emit list originals with action='reorder' in LLM prompts
- Validate raw LLM change dicts with is_valid_change before model construction
- Add unit tests covering each action with both string and list originals
When it happens
Trigger: Constructing or parsing a ResumeChange (e.g. from LLM JSON output via ImproveDiffResult) where original is a list (e.g. ["item1","item2"]) but action is 'replace', 'add', or 'delete' instead of 'reorder'.
Common situations: LLM emits malformed change items; prompt/schema drift causes the model to send the current items list for a text edit; code that reuses the reorder payload shape for other actions.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Resume preview data is invalid.
- answer text must not be blank
- answer is required for answer actions
- personalInfo.name is required
- ${message = data.detail or Failed to update LLM config (stat
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/9101f0c6a37f0870.
Report an issue: GitHub.