hiyouga/LlamaFactory · error · ValueError

ep_size must be positive, got {self.ep_size}.

Error message

ep_size must be positive, got {self.ep_size}.

What it means

ValueError from FSDP2Params.__post_init__ (interface.py:59) validating that ep_size is at least 1. It fires at config-parse time, before any distributed setup, when a non-positive expert-parallel size is supplied. This is a strict guard against typo'd or computed-to-zero ep_size values.

Source

Thrown at src/llamafactory/v1/plugins/trainer_plugins/distributed/interface.py:59

    dcp_path: str | None = None


@dataclass
class FSDPTurboParams:
    name: Literal["fsdpturbo"] = "fsdpturbo"
    reshard_after_forward: bool = True
    offload_params: bool = False
    pin_memory: bool = True
    dcp_path: str | None = None
    ep_size: int = 1
    ep_dispatcher: str = "eager"
    fsdp_ignored_modules: list[str] = field(default_factory=list)
    hook_modules: list[str] = field(default_factory=list)
    fsdp_implementation: str = "native"

    def __post_init__(self) -> None:
        if self.ep_size < 1:
            raise ValueError(f"ep_size must be positive, got {self.ep_size}.")


@dataclass
class DeepSpeedParams:
    name: Literal["deepspeed"] = "deepspeed"
    config_file: str = ""

    def __post_init__(self) -> None:
        if not self.config_file:
            raise ValueError("DeepSpeed config_file is required.")


class DistributedPlugin(BasePlugin):
    """Plugin family for distributed training backends."""


@DistributedPlugin("fsdp2").register()
class FSDP2Distributed(BaseDistributed):

View on GitHub (pinned to f28afaf635)

Solutions

  1. Set ep_size to 1 (no expert parallelism) or a positive divisor of world size.
  2. If the value is computed, validate it before constructing FSDP2Params and fall back to 1 when the computation yields <= 0.
  3. Re-check the YAML/JSON config for a mistyped ep_size key value.

Example fix

# before
FSDP2Params(ep_size=world_size // 16)  # 0 when world_size < 16

# after
FSDP2Params(ep_size=max(1, world_size // 16))
Defensive patterns

Strategy: validation

Validate before calling

assert isinstance(ep_size, int) and ep_size >= 1, f"ep_size must be >= 1, got {ep_size}"

Type guard

def is_valid_ep_size(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool) and v >= 1

Prevention

When it happens

Trigger: Passing ep_size: 0 or a negative value in the dist_config mapping for the fsdp2/fsdpturbo plugin; or computing ep_size programmatically (e.g. world_size // num_nodes) and passing 0 when the division underflows.

Common situations: YAML typo (ep_size: 0), templated configs where a variable evaluates to 0, or scripts that derive ep_size from environment variables defaulting to 0.

Related errors


AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14). Data as JSON: /api/errors/72fddbabcd5b1067. Report an issue: GitHub.