{"record":{"id":"9c04fc2c1fb4fa52","repo":"huggingface/transformers","slug":"can-only-set-a-dictionary-as-pp-plan","errorCode":null,"errorMessage":"Can only set a dictionary as `pp_plan`","messagePattern":"Can only set a dictionary as `pp_plan`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/distributed/mixin.py","lineNumber":146,"sourceCode":"            for param_name in model_param_names:\n                if re.match(regex_pattern, param_name):\n                    pattern_matched = True\n                    break\n            if not pattern_matched:\n                warnings.warn(\n                    f\"Layer pattern '{layer_pattern}' does not match any parameters in the model. This rule may not \"\n                    \"be applied during tensor parallelization, or may lead to dimension mismatches\"\n                )\n\n        self._tp_plan = plan\n\n    @pp_plan.setter\n    def pp_plan(self, plan: dict[str, tuple[str, str]] | None):\n        if plan is None:\n            self._pp_plan = {}\n            return\n        if not isinstance(plan, dict):\n            raise ValueError(\"Can only set a dictionary as `pp_plan`\")\n\n        self._pp_plan = plan\n\n    @classmethod\n    def prepare_distribute_model(\n        cls,\n        distributed_config: DistributedConfig | dict | None,\n        *,\n        device_mesh=None,\n        device_map=None,\n    ) -> tuple[DistributedConfig | None, object, object]:\n        if distributed_config is None:\n            return None, device_map, device_mesh\n\n        if isinstance(distributed_config, dict):\n            distributed_config = DistributedConfig.from_dict(distributed_config)\n\n        if distributed_config.tp_size > 1 or distributed_config.fsdp_size > 1:","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/distributed/mixin.py#L128-L164","documentation":"The pp_plan setter only accepts None (which resets the plan to an empty dict) or a dictionary mapping layer patterns to (input_module_id, output_module_id) tuples. Passing any other type (a string, list, or a plan object) raises this ValueError immediately, before any pipeline-parallel setup runs.","triggerScenarios":"model.pp_plan = 'auto' or model.pp_plan = [('layers.0', (0, 0)), ...] — anything that is not a dict[str, tuple[str, str]] and not None.","commonSituations":"Confusing pp_plan with tp_plan, which additionally accepts the string 'auto'; passing a parsed YAML/JSON value that became a list; passing a PipelineParallelismPlan-like object instead of the raw dict.","solutions":["Pass a dict of the form {layer_pattern: (input_placeholder_id, output_placeholder_id)} or None.","If you do not want pipeline parallelism, set pp_plan = None (or omit it) instead of an empty string.","Check that YAML/JSON config loading produced a dict, not a list of pairs."],"exampleFix":"# before\nmodel.pp_plan = \"auto\"\n\n# after\nmodel.pp_plan = {\"model.layers.*\": (\"model.embed_tokens\", \"lm_head\")}","handlingStrategy":"type-guard","validationCode":"def validate_pp_plan(plan) -> None:\n    if plan is None:\n        return\n    if not isinstance(plan, dict):\n        raise TypeError(\"pp_plan must be a dict[layer_pattern, tuple[str, str]] or None\")\n    for k, v in plan.items():\n        if not (isinstance(v, tuple) and len(v) == 2 and all(isinstance(x, str) for x in v)):\n            raise ValueError(f\"pp_plan['{k}'] must be (input_module_id, output_module_id)\")","typeGuard":"def is_valid_pp_plan(plan: object) -> bool:\n    if plan is None:\n        return True\n    return isinstance(plan, dict) and all(\n        isinstance(v, tuple) and len(v) == 2 and all(isinstance(s, str) for s in v)\n        for v in plan.values()\n    )","tryCatchPattern":"try:\n    model.pp_plan = plan\nexcept ValueError as e:\n    if \"Can only set a dictionary\" in str(e):\n        raise TypeError(f\"pp_plan must be a dict, got {type(plan).__name__}\") from e\n    raise","preventionTips":["pp_plan has no 'auto' string — only dict or None.","Type your config fields (dict[str, tuple[str, str]] | None) so mypy catches mistakes.","Validate YAML-loaded configs before assigning."],"tags":["pipeline-parallel","distributed","config","type-error"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}