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-rc2become2.4.rc2 - Delegates parsing to
parse_model_versionfor 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_versionmetadata 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_versionfrom.safetensorsmetadata, 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.pyfor detection logic,helpers.pyfor parsing,CLAUDE.mdfor parameter defaults, andREADME.mdfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →