LTX-2 Model Version Detection Rules and Checkpoint Format Differences Explained

LTX-2 determines a checkpoint's generation by reading the model_version metadata field from its .safetensors file, normalizing separators, and parsing leading numeric components into a comparable tuple, while LTX-2.3 and LTX-2.S (original) checkpoints share a unified file layout but differ in STG block indices, step counts, and Gemma versions.

This guide examines the version detection algorithm and checkpoint format distinctions between LTX-2.3 and LTX-2.S (the original "S" family, including LTX-2.5) based on the official Lightricks/LTX-2 source code. Understanding these differences ensures you load the correct pipeline parameters for each checkpoint generation.


How LTX-2 Detects Model Versions from Checkpoints

The model version detection system reads checkpoint metadata and converts version strings into comparable tuples. This process flows through two core functions in the pipeline utilities.

Step 1: Extract and Normalize Version Metadata

The detection begins in ltx-pipelines/src/ltx_pipelines/utils/constants.py with detect_model_version:

def detect_model_version(checkpoint_path: Path) -> tuple[int, ...]:
    """
    Reads the metadata of the checkpoint and returns the model version as a tuple.
    Tuples of the form `(2, 3)`, `(2, 5)` are returned for valid versions.
    """
    with safe_open(checkpoint_path, framework="pt") as f:
        metadata = f.metadata()
        version_string = metadata.get("model_version", None)

    if version_string is None:
        return ()

    # Normalize separators: "2.4-rc2" → "2.4.rc2"

    version_string = version_string.replace("-", ".")
    return parse_model_version(version_string)

This function performs three critical normalizations:

  • Replaces hyphens with dots so pre-release tags like 2.4-rc2 become 2.4.rc2
  • Delegates parsing to parse_model_version for numeric extraction
  • Returns an empty tuple () when the field is missing or unreadable

Step 2: Parse Numeric Components

The parsing logic lives in ltx-core/src/ltx_core/loader/helpers.py:

def parse_model_version(version_string: str) -> tuple[int, ...]:
    """
    Parse a model version string into a tuple of integers.
    
    Only leading numeric components are kept; suffixes like 'rc' or 'beta' are discarded
    """
    components = version_string.split(".")
    version_tuple = []
    for component in components:
        if component.isdigit():
            version_tuple.append(int(component))
        else:
            break
    return tuple(version_tuple)

This parser stops at the first non-numeric component, discarding tags like rc, beta, or alpha. The result is a clean tuple such as (2, 3) or (2, 5) that supports direct comparison operations.

Step 3: Map Version to Pipeline Parameters

The detect_params function (also in constants.py) uses tuple comparison against _PARAMS_SINCE_VERSION:

def detect_params(checkpoint_path: Path) -> LTXParams:
    """Detect the appropriate LTXParams for a given checkpoint."""
    version_tuple = detect_model_version(checkpoint_path)
    
    # Iterate from newest to oldest, return first match

    for since_version, params in reversed(_PARAMS_SINCE_VERSION):
        if version_tuple >= since_version:
            return params
    return LTX_2_PARAMS  # Oldest fallback

The version tuple (2, 3) selects LTX_2_3_PARAMS, while (2, 5) selects LTX_2_5_PARAMS. The empty tuple () compares below all real versions, triggering the legacy LTX_2_PARAMS fallback for checkpoints without metadata.


Checkpoint Format Differences: LTX-2.3 vs LTX-2.S

Despite sharing a unified file structure, these generations differ in generation-specific defaults, Gemma versions, and pipeline configuration.

Unified Checkpoint Layout (Both Generations)

Both LTX-2.3 and LTX-2.S use the same physical format as documented in packages/ltx-trainer/README.md:

Component Location
Transformer weights Single .safetensors file
Video VAE Embedded in same .safetensors
Audio VAE Embedded in same .safetensors
Vocoder Embedded in same .safetensors
Text encoder (Gemma) Separate folder alongside .safetensors

The README.md states: "The unified checkpoint format works for LTX-2, LTX-2.3, and LTX-2.5—all model weights live in a single file with the Gemma folder containing text encoder weights."

Generation-Specific Differences

Feature LTX-2.3 LTX-2.S (Original/2.5)
model_version field "2.3" or "2.3.rcX" "2", "2.0", or omitted
Detection result (2, 3) () (empty tuple → fallback)
Gemma version Gemma 3 Gemma 3 (2.0) / Gemma 4 (2.5)
STG block index Block 28 Block 29
Default steps (full model) 30 40
Default image CRF 33 33 (2.0) / 18 (2.4+)

These defaults are resolved through detect_params and applied in packages/ltx-pipelines/CLAUDE.md, which documents: "STG is applied to block 29 for LTX-2 and LTX-2.S, versus block 28 for LTX-2.3."

Gemma Version Validation

The loader validates Gemma compatibility in ltx_core/loader/module_ops.py via _check_gemma_version. Both generations require matching between:

  • The gemma_version metadata entry in the checkpoint
  • The actual Gemma folder contents

LTX-2.5 checkpoints specify Gemma 4, while LTX-2.3 and early LTX-2 use Gemma 3.


Practical Code Examples

Detect Version and Load Correct Parameters

from ltx_pipelines.utils.constants import detect_model_version, detect_params
from pathlib import Path

# Path to any LTX-2 family checkpoint

ckpt_path = Path("checkpoints/ltx-2.3-22b.safetensors")

# Extract version tuple

version = detect_model_version(ckpt_path)
print(f"Detected version: {version}")  # → (2, 3)

# Automatically select generation-specific defaults

params = detect_params(ckpt_path)
print(f"Steps: {params.steps}")        # → 30

print(f"STG blocks: {params.stg_blocks}")  # → [28]

Conditional Logic Based on Version

from ltx_pipelines.utils.constants import LTX_2_3_PARAMS, LTX_2_5_PARAMS

version = detect_model_version(ckpt_path)

if version >= (2, 5):
    print("LTX-2.5+ detected: using 20 steps, Gemma 4, CRF 18")
    # Override with 2.5-specific behavior

elif version >= (2, 3):
    print("LTX-2.3 detected: 30 steps, Gemma 3, STG block 28")
    params = LTX_2_3_PARAMS
elif version >= (2,):
    print("LTX-2.0-2.1 detected: 40 steps, Gemma 3, STG block 29")
else:
    print("Unknown/legacy checkpoint: using safest fallback defaults")

Inspect Checkpoint Metadata Directly

from safetensors import safe_open

with safe_open(ckpt_path, framework="pt") as f:
    metadata = f.metadata()
    print("Raw model_version:", metadata.get("model_version", "NOT FOUND"))
    print("Gemma version:", metadata.get("gemma_version", "NOT FOUND"))
    
    # All available metadata keys

    print("All keys:", list(metadata.keys()))

Summary

  • Version detection reads model_version from .safetensors metadata, normalizes hyphens to dots, and parses leading numeric components into comparable tuples like (2, 3) or ().
  • Empty tuple () indicates missing or unparsable versions, triggering the oldest parameter fallback.
  • Unified checkpoint format bundles transformer, VAEs, and vocoder in one file with a separate Gemma folder for both generations.
  • Key differences: LTX-2.3 uses STG block 28 and 30 steps; LTX-2.S uses STG block 29 and 40 steps (original) or switches to Gemma 4 (2.5).
  • Source files: constants.py for detection logic, helpers.py for parsing, CLAUDE.md for parameter defaults, and README.md for checkpoint layout.

Frequently Asked Questions

What happens if a checkpoint has no model_version metadata?

The detection returns an empty tuple (), which compares below all real versions. This triggers LTX_2_PARAMS—the oldest fallback defaults with 40 steps, STG block 29, and CRF 33. This behavior ensures backward compatibility with early LTX-2 checkpoints created before version metadata was standardized.

How does the hyphen normalization affect version comparison?

Hyphens are replaced with dots before parsing, so 2.4-rc2 becomes 2.4.rc2, then parses to (2, 4). The rc2 suffix is discarded because parse_model_version stops at the first non-numeric component. This means pre-release builds map to their base version's parameter set.

Can I force specific parameters regardless of detected version?

Yes—detect_params is a convenience helper. You can import and instantiate parameter classes directly: from ltx_pipelines.utils.constants import LTX_2_3_PARAMS and use LTX_2_3_PARAMS explicitly. The detection system only automates what you could configure manually.

Why do LTX-2.3 and LTX-2.5 share the "S" designation in some documentation?

The "S" (Standard) family originally referred to the base LTX-2 architecture. LTX-2.3 represents a significant generation with its own parameter set, while LTX-2.5 returns to the S lineage with upgraded components (Gemma 4, refined defaults). The unified checkpoint format masks these differences at the file level—the detection system resolves them at runtime.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →