{"record":{"id":"9bea356b9b041ac5","repo":"huggingface/transformers","slug":"type-model-name-does-not-have-a-fsdp2-plan","errorCode":null,"errorMessage":"{type(model).__name__} does not have a FSDP2 plan declared. Set `base_model_fsdp_plan` on the config and `_fsdp_plan` on the head class.","messagePattern":"(.+?) does not have a FSDP2 plan declared\\. Set `base_model_fsdp_plan` on the config and `_fsdp_plan` on the head class\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/distributed/fsdp.py","lineNumber":198,"sourceCode":"\n    if invalid_strategies:\n        logger.warning(f\"The following FSDP entries have unknown strategies: {invalid_strategies}\")\n    if unused_rules:\n        logger.warning(f\"The following FSDP rules were not applied to any module: {unused_rules}\")\n\n\ndef apply_fully_sharded_data_parallelism(\n    model: nn.Module, fsdp_mesh: torch.distributed.device_mesh.DeviceMesh\n) -> nn.Module:\n    \"\"\"\n    Apply FSDP2 (fully_shard) to a model.\n\n    Torch availability, distributed initialization and the version requirement\n    are asserted upstream by `initialize_fully_sharded_data_parallelism`.\n    \"\"\"\n    fsdp_plan = dict(getattr(model, \"_fsdp_plan\", None) or {})\n    if not fsdp_plan:\n        raise ValueError(\n            f\"{type(model).__name__} does not have a FSDP2 plan declared. Set \"\n            \"`base_model_fsdp_plan` on the config and `_fsdp_plan` on the head class.\"\n        )\n\n    distributed_config = getattr(model.config, \"distributed_config\", None)\n    fsdp_policy_kwargs = _get_fsdp_policy_kwargs(distributed_config)\n\n    adapted_fsdp_plan = _resolve_tied_embed_lm_head_plan(fsdp_plan, model)\n    reshard_targets, no_reshard_targets = expand_fsdp_plan(model, adapted_fsdp_plan)\n\n    for module_name, module in reshard_targets:\n        fully_shard(module, mesh=fsdp_mesh, reshard_after_forward=True, **fsdp_policy_kwargs)\n        logger.debug(f\"Applied fully_shard to {module_name} (reshard=True)\")\n\n    # Optimization: when the keep buffer is exactly the (final_norm, lm_head/embed)\n    # tail pair, bundle them into one fully_shard so that we dont need to do all-gather during backward pass.\n    if is_norm_and_head_pair(no_reshard_targets, model):\n        names, modules = [], []","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/distributed/fsdp.py#L180-L216","documentation":"When applying FSDP2 (torch's fully_shard), transformers requires each model class to declare which modules to wrap via an _fsdp_plan (derived from base_model_fsdp_plan on the config and _fsdp_plan on the head class). apply_fully_sharded_data_parallelism reads that plan; if the model exposes none, it refuses to guess a sharding strategy and raises. Models must opt in by declaring a plan.","triggerScenarios":"Enabling fsdp_size>1 in DistributedConfig and calling the FSDP2 setup path on a model whose architecture has no base_model_fsdp_plan in its config; applying apply_fully_sharded_data_parallelism directly to a custom/naive nn.Module; a newer model integration missing the plan declaration.","commonSituations":"FSDP training of a model family that has not yet declared an FSDP2 plan; custom model heads built outside the standard PreTrainedModel conventions; version skew where the plan mechanism is newer than the model file.","solutions":["Use a model that declares an FSDP2 plan (check its config for base_model_fsdp_plan / the class for _fsdp_plan).","For your own model, declare the plan: set base_model_fsdp_plan on the config class and _fsdp_plan on the head class mapping module patterns to shard groups.","If the model cannot be migrated, fall back to torch's native FSDP1 wrapping or plain DDP instead of this helper."],"exampleFix":"# before\ncfg = DistributedConfig(fsdp_size=8)\n# model has no plan -> apply_fully_sharded_data_parallelism raises\n\n# after: declare a plan on the model\nclass MyModelConfig(PretrainedConfig):\n    base_model_fsdp_plan = {\"language_model.layers.*\": \"full_shard\"}\n\nclass MyModel(PreTrainedModel):\n    _fsdp_plan = {\"language_model.layers.*\": \"full_shard\"}\n# now fsdp_size=8 setup proceeds","handlingStrategy":"validation","validationCode":"fsdp_plan = getattr(type(model), \"_fsdp_plan\", None) or getattr(model, \"_fsdp_plan\", None)\nif distributed_config.fsdp_size and not fsdp_plan:\n    raise ValueError(f\"{type(model).__name__} lacks an FSDP2 plan; pick a supported model or declare one\")","typeGuard":"def has_fsdp_plan(model) -> bool:\n    return bool(getattr(model, \"_fsdp_plan\", None))","tryCatchPattern":"try:\n    model = apply_fully_sharded_data_parallelism(model, mesh)\nexcept ValueError as e:\n    if \"does not have a FSDP2 plan\" in str(e):\n        # fall back to DDP or a plan-declaring model\n        model = model.to(rank)\n    else:\n        raise","preventionTips":["Check for _fsdp_plan on the model class before enabling fsdp_size>1.","Declare base_model_fsdp_plan/_fsdp_plan for custom models.","Track which model integrations support FSDP2 when upgrading."],"tags":["distributed","fsdp2","model-integration","sharding"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}