Skip to content

Fix MiniMax-H3 refusing the 15-second clip its envelope declares - #14742

Open
PaulFidika wants to merge 1 commit into
huggingface:mainfrom
PaulFidika:minimax-h3-frame-grid-bounds
Open

Fix MiniMax-H3 refusing the 15-second clip its envelope declares#14742
PaulFidika wants to merge 1 commit into
huggingface:mainfrom
PaulFidika:minimax-h3-frame-grid-bounds

Conversation

@PaulFidika

Copy link
Copy Markdown

What

MiniMaxH3PrepareLayoutStep (before_denoise.py) and MiniMaxH3Ref2VASetupStep (before_encoder.py) snap num_frames up onto the video VAE's 17 * n + 5 grid and then check the aligned count against [min_duration, max_duration] expressed in seconds.

The two ends of the envelope are not treated alike, and at MiniMax-H3's own numbers (24 fps, min_duration=5.0, max_duration=15.0) the inconsistency is visible:

num_frames aligned seconds today
120 124 5.167 admitted, though 5.167 > 5.0
345 345 14.375 admitted
346 362 15.083 refused, though 362 = 17 * 21 + 5

The floor tolerates the upward snap; the ceiling does not. And the grid has no point at 15.0 * 24 = 360 — its neighbours are 345 (14.375 s) and 362 (15.083 s) — so a model documented as generating "between 5.0 and 15.0 seconds" cannot currently generate 15 seconds at all. The longest clip it will produce is 14.375 s.

Repro

from diffusers import MiniMaxH3Blocks, MiniMaxH3ModularPipeline

pipe = MiniMaxH3ModularPipeline(blocks=MiniMaxH3Blocks().get_workflow("fl2va"))
pipe(prompt="...", num_frames=362)  # 17 * 21 + 5, a legal grid point
# ValueError: MiniMax-H3 generates between 5.0 and 15.0 seconds at 24 fps, so `num_frames`,
# rounded up to the next `17 * n + 5` the video VAE can encode, must be between 120 and 360,
# got 362 (rounded up to 362).

Note the message names 120 and 360 as the bounds; neither is a frame count the VAE can encode.

Change

Carry the declared envelope onto the grid at both ends, with the same upward snap the request gets, via a small frame_bounds helper next to align_num_frames. The bound the VAE actually has is a frame count, so that is where the check belongs; the clock only reads it.

For MiniMax-H3 the admitted band becomes [124, 362] frames:

  num_frames= 107 -> aligned  107 ( 4.458s)  admitted=False
  num_frames= 120 -> aligned  124 ( 5.167s)  admitted=True
  num_frames= 345 -> aligned  345 (14.375s)  admitted=True
  num_frames= 346 -> aligned  362 (15.083s)  admitted=True
  num_frames= 362 -> aligned  362 (15.083s)  admitted=True
  num_frames= 363 -> aligned  379 (15.792s)  admitted=False

Every count that was already accepted keeps its verdict, and the band stays bounded — 379 is still refused. The only counts that change verdict are those aligning to 362, which the model's declared 15-second ceiling should always have covered. The error message now names the real frame bounds.

Evidence that 362 is a capability the model has

362 frames is a legal chunk boundary (17 * 21 + 5), nothing in the model is length-bound at that scale — RoPE is computed per request and both VAEs are chunked convolutions — and hosted MiniMax-H3 endpoints ship 362-frame clips today. Preparation at 362 resolves cleanly through the official blocks once the seconds ceiling no longer misfires, producing a packed sequence of 109,062 rows at 1344x768.

🤖 Generated with Claude Code

https://claude.ai/code/session_019xrGKGkMTvR3BRuK58Z1mo

`MiniMaxH3PrepareLayoutStep` and `MiniMaxH3Ref2VASetupStep` snap `num_frames`
up onto the video VAE's `17 * n + 5` grid and then check the *aligned* count
against `[min_duration, max_duration]` in seconds. The two ends are not
treated alike, and at MiniMax-H3's own numbers that is visible:

- the floor tolerates the snap: `num_frames=120` aligns to 124 = 5.167 s and
  is admitted, though 5.167 > 5.0;
- the ceiling does not: 362 frames = 15.083 s is refused, though 362 is
  `17 * 21 + 5`, a legal grid point.

The grid has no point at `15.0 * 24 = 360`. Its neighbours are 345 (14.375 s)
and 362 (15.083 s), so a model documented as generating up to 15 seconds
cannot currently generate 15 seconds at all — the longest clip it will produce
is 14.375 s.

Carry the declared envelope onto the grid at both ends instead, with the same
upward snap a request gets, via a small `frame_bounds` helper. For MiniMax-H3
this makes the admitted band `[124, 362]` frames. Behaviour is unchanged for
every count that was already accepted; the only counts that change verdict are
those aligning to 362, which the model's own declared 15-second ceiling should
always have covered.

The error message now names the real frame bounds rather than
`int(min_duration * fps)` / `int(max_duration * fps)`, which reported 120 and
360 — neither of which is a frame count the VAE can encode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added size/M PR with diff < 200 LOC modular-pipelines and removed size/M PR with diff < 200 LOC labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Hi @PaulFidika, thanks for the PR! It does not appear to link an issue it fixes. If this PR addresses an existing issue, please add a closing keyword (e.g. Fixes #1234) to the PR description so the issue is linked. See the contribution guide for more details. If this PR intentionally does not fix a tracked issue, a maintainer can add the no-issue-needed label to silence this reminder.

Please note that PRs without a linked issue are likely to be automatically closed 10 days after this notice.

Once the PR links an issue (or gets the no-issue-needed label), you can ignore this message — it stays here as a comment, but it no longer applies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant