{"record":{"id":"467ed08909d4b767","repo":"pytorch/pytorch","slug":"pattern-must-contain-a-single-separator","errorCode":null,"errorMessage":"Pattern must contain a single '->' separator","messagePattern":"Pattern must contain a single '->' separator","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"functorch/einops/_parsing.py","lineNumber":227,"sourceCode":"\ndef parse_pattern(\n    pattern: str, axes_lengths: Mapping[str, int]\n) -> tuple[ParsedExpression, ParsedExpression]:\n    \"\"\"Parse an `einops`-style pattern into a left-hand side and right-hand side `ParsedExpression` object.\n\n    Args:\n        pattern (str): the `einops`-style rearrangement pattern\n        axes_lengths (Mapping[str, int]): any additional length specifications for dimensions\n\n    Returns:\n       tuple[ParsedExpression, ParsedExpression]: a tuple containing the left-hand side and right-hand side expressions\n    \"\"\"\n    # adapted from einops.einops._prepare_transformation_recipe\n    # https://github.com/arogozhnikov/einops/blob/230ac1526c1f42c9e1f7373912c7f8047496df11/einops/einops.py\n    try:\n        left_str, right_str = pattern.split(\"->\")\n    except ValueError:\n        raise ValueError(\"Pattern must contain a single '->' separator\") from None\n\n    if _ellipsis in axes_lengths:\n        raise ValueError(f\"'{_ellipsis}' is not an allowed axis identifier\")\n\n    left = ParsedExpression(left_str)\n    right = ParsedExpression(right_str)\n\n    if not left.has_ellipsis and right.has_ellipsis:\n        raise ValueError(\n            f\"Ellipsis found in right side, but not left side of a pattern {pattern}\"\n        )\n    if left.has_ellipsis and left.has_ellipsis_parenthesized:\n        raise ValueError(\n            f\"Ellipsis is parenthesis in the left side is not allowed: {pattern}\"\n        )\n\n    return left, right\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/pytorch/pytorch/blob/dcd2ecae775af66439b7ede4e7a82540b058c59c/functorch/einops/_parsing.py#L209-L245","documentation":"Thrown by `_split_pattern`/`parse_pattern` in functorch/einops `_parsing.py`. `pattern.split('->')` must yield exactly two parts; zero separators or more than one `->` raises this ValueError (the original exception is suppressed with `from None`).","triggerScenarios":"Patterns with no `->` (`'b c'`) or with multiple `->` (`'a -> b -> c'`, or a side containing '->' after template concatenation).","commonSituations":"Missing arrow when writing a quick pattern; chaining attempted in one string; pattern strings built by joining fragments that each contain an arrow.","solutions":["Ensure the pattern has exactly one `->` separating left and right sides","Chain multiple rearrange calls instead of trying to encode multiple steps in one pattern","Validate `pattern.count('->') == 1` before calling the API"],"exampleFix":"# before\ny = rearrange(x, 'b (h w)')  # missing '->'\n\n# after\ny = rearrange(x, 'b (h w) -> b h w')","handlingStrategy":"validation","validationCode":"def has_single_arrow(pattern: str) -> bool:\n    return pattern.count(\"->\") == 1","typeGuard":null,"tryCatchPattern":"try:\n    y = rearrange(x, pattern)\nexcept ValueError as e:\n    if \"single '->' separator\" in str(e):\n        raise ValueError(f\"pattern {pattern!r} needs exactly one '->'\") from e\n    raise","preventionTips":["Always write both sides: 'input_axes -> output_axes'","Chain rearrange calls instead of multi-arrow patterns"],"tags":["einops","parsing","pattern","separator"],"backgroundTag":null,"analyzedSha":"dcd2ecae775af66439b7ede4e7a82540b058c59c","analyzedAt":"2026-08-14T19:21:26.615Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}