Bug: mmx quota show reports "100% remaining" for video, but mmx video generate rejects with (0/0 used) — quota endpoint and generation endpoint give contradictory data
Summary
mmx quota show (text and JSON mode) reports 100% remaining for the video model on a Token Plan Plus plan. mmx video generate against the same API key, in the same session, is rejected with usage limit exceeded, weekly usage limit reached for Token Plan Plus (0/0 used). The two endpoints — /v1/token_plan/remains (quota show) and /v1/video_generation (generate) — return semantically contradictory data, so the CLI ends up confidently telling the user "you have 100% video quota" and then immediately refusing the request. There is no plan that lets the user discover the 0/0 allowance from the quota screen.
This is a follow-up to #165 (closed in v1.0.16). That fix made the panel render the percent / time fields correctly, but it surfaced — and is now load-bearing on — a server-side inconsistency: current_interval_remaining_percent: 100 is being returned for a model whose weekly allowance is literally 0.
Environment
mmx-cli 1.0.16 (mmx --version)
- Node 18+ (running on macOS)
- Auth: API key (
mmx auth status → api-key)
- Region:
cn (base url https://api.minimaxi.com)
- Plan: Token Plan Plus
Steps to reproduce
mmx auth login --api-key sk-... with a Token Plan Plus key.
mmx quota show — observe the video row says 100% remaining, 100% weekly remaining, "resets in 6h 42m".
mmx video generate --first-frame 1.png --prompt "..." --download out.mp4 — the call is rejected.
- (Optional) Re-run the same call as a direct
curl against /v1/video_generation with duration: 10, resolution: "768P" to bypass any CLI serialization.
Actual output
mmx quota show --output json (relevant row, model_name: "video")
{
"model_name": "video",
"start_time": 1780848000000,
"end_time": 1780934400000,
"remains_time": 23965834,
"current_interval_total_count": 0,
"current_interval_usage_count": 0,
"current_weekly_total_count": 0,
"current_weekly_usage_count": 0,
"current_interval_status": 3,
"current_weekly_status": 3,
"current_interval_remaining_percent": 100,
"current_weekly_remaining_percent": 100
}
Notice: counts are 0/0, both statuses are 3 (different from general, which is 1), yet *_remaining_percent is 100.
mmx quota show (text mode, region = cn)
| video 100% 剩余 [................] 0% |
| └ 每周 100% 剩余 重置于 6h 39m |
(The general row, in the same response, correctly shows 63% / 96% remaining with non-zero counts.)
mmx video generate response
{
"task_id": "",
"base_resp": {
"status_code": 2056,
"status_msg": "usage limit exceeded, weekly usage limit reached for Token Plan Plus (0/0 used), resets at 2026-06-15T00:00:00+08:00"
}
}
status_code: 2056, message explicitly says (0/0 used) for the same plan + same model + same week that quota show reported as 100% remaining.
Expected output
The quota endpoint should agree with the generation endpoint. Concretely, one of:
- Server-side fix (preferred) — when the model is not part of the user's plan (e.g.
current_interval_total_count === 0 AND current_weekly_total_count === 0 AND *_status === 3), the /v1/token_plan/remains response should return something the CLI can show truthfully:
current_interval_remaining_percent: 0 and current_weekly_remaining_percent: 0 (consistent with (0/0 used)), or
- a new field like
model_name: "video", available_in_plan: false (or an explicit status: "not_in_plan") so the CLI can render "video — not in your Token Plan Plus" instead of a misleading "100% remaining".
- CLI-side fallback — if the server is hard to change, the CLI could detect
current_interval_total_count === 0 && current_weekly_total_count === 0 && current_interval_status === 3 and render the row as 0% 剩余 — not in your current plan (or similar) so the user is not sent straight into mmx video generate only to be turned away with 2056.
Either way, the user-facing experience should not say "100% remaining" and then "0/0 used" within the same minute for the same plan.
Root cause (hypothesis)
The /v1/token_plan/remains response is being computed in a way that conflates "no usage so far" with "no allowance at all". For plans where a model is not bundled (Token Plan Plus does not include video), the server returns:
- count fields =
0 (correct: there is no quota bucket)
- percent fields =
100 (wrong: this is computed as 100% of 0, not as a real remaining-quota signal)
- status =
3 (a status code whose meaning is undocumented in the public API; "not in plan" is the only interpretation consistent with the generation endpoint's (0/0 used))
Meanwhile /v1/video_generation enforces the real plan: (0/0 used) because the model is not in the plan at all. The two endpoints are not derived from the same source of truth.
The fix in #165 made the panel render the percent fields, which now carries this inconsistency straight to the user.
Suggested fix
Option A — server-side (preferred)
Make /v1/token_plan/remains and /v1/video_generation agree. Concretely, when a model is not bundled in the user's plan:
{
"model_name": "video",
"current_interval_total_count": 0,
"current_interval_usage_count": 0,
"current_weekly_total_count": 0,
"current_weekly_usage_count": 0,
"current_interval_remaining_percent": 0,
"current_weekly_remaining_percent": 0,
"current_interval_status": 4, // new: "not_in_plan"
"current_weekly_status": 4,
"not_in_plan": true
}
…so the CLI can render video — 不在当前套餐中 / not in your plan, and the user can decide whether to upgrade before re-running the generation call.
Option B — CLI-side guardrail (defense in depth, can ship immediately)
In mmx quota show, when current_interval_total_count === 0 && current_weekly_total_count === 0 && current_interval_status !== 1 (the "no bucket" case), render the row as:
| video 不在当前套餐中 [................] 0% |
| └ 每周 不在当前套餐中 — |
…regardless of what the *_remaining_percent fields say. This way the user is never told "100% remaining" for a model they cannot use.
Bonus: a preflight check in mmx video generate — if the quota endpoint reports this "no bucket" state, fail fast with a clear error like video generation is not included in your Token Plan Plus. Upgrade your plan at <url>. instead of submitting a task and getting a 2056 back. The current 2056 message is correct, but only the user who reads the raw JSON sees it; the CLI swallows the message into a generic "Task failed" unless --verbose is on.
Related
Reproduction environment
- macOS 15.x
mmx 1.0.16
- API endpoint 1:
GET https://api.minimaxi.com/v1/token_plan/remains
- API endpoint 2:
POST https://api.minimaxi.com/v1/video_generation
- Reproduction key: Token Plan Plus, region
cn, video model = MiniMax-Hailuo-2.3 (default)
Bug:
mmx quota showreports "100% remaining" for video, butmmx video generaterejects with(0/0 used)— quota endpoint and generation endpoint give contradictory dataSummary
mmx quota show(text and JSON mode) reports100% remainingfor thevideomodel on a Token Plan Plus plan.mmx video generateagainst the same API key, in the same session, is rejected withusage limit exceeded, weekly usage limit reached for Token Plan Plus (0/0 used). The two endpoints —/v1/token_plan/remains(quota show) and/v1/video_generation(generate) — return semantically contradictory data, so the CLI ends up confidently telling the user "you have 100% video quota" and then immediately refusing the request. There is no plan that lets the user discover the 0/0 allowance from the quota screen.This is a follow-up to #165 (closed in v1.0.16). That fix made the panel render the percent / time fields correctly, but it surfaced — and is now load-bearing on — a server-side inconsistency:
current_interval_remaining_percent: 100is being returned for a model whose weekly allowance is literally0.Environment
mmx-cli 1.0.16(mmx --version)mmx auth status→api-key)cn(base urlhttps://api.minimaxi.com)Steps to reproduce
mmx auth login --api-key sk-...with a Token Plan Plus key.mmx quota show— observe thevideorow says 100% remaining, 100% weekly remaining, "resets in 6h 42m".mmx video generate --first-frame 1.png --prompt "..." --download out.mp4— the call is rejected.curlagainst/v1/video_generationwithduration: 10, resolution: "768P"to bypass any CLI serialization.Actual output
mmx quota show --output json(relevant row,model_name: "video"){ "model_name": "video", "start_time": 1780848000000, "end_time": 1780934400000, "remains_time": 23965834, "current_interval_total_count": 0, "current_interval_usage_count": 0, "current_weekly_total_count": 0, "current_weekly_usage_count": 0, "current_interval_status": 3, "current_weekly_status": 3, "current_interval_remaining_percent": 100, "current_weekly_remaining_percent": 100 }Notice: counts are
0/0, both statuses are3(different fromgeneral, which is1), yet*_remaining_percentis100.mmx quota show(text mode, region = cn)(The general row, in the same response, correctly shows 63% / 96% remaining with non-zero counts.)
mmx video generateresponse{ "task_id": "", "base_resp": { "status_code": 2056, "status_msg": "usage limit exceeded, weekly usage limit reached for Token Plan Plus (0/0 used), resets at 2026-06-15T00:00:00+08:00" } }status_code: 2056, message explicitly says(0/0 used)for the same plan + same model + same week thatquota showreported as 100% remaining.Expected output
The quota endpoint should agree with the generation endpoint. Concretely, one of:
current_interval_total_count === 0ANDcurrent_weekly_total_count === 0AND*_status === 3), the/v1/token_plan/remainsresponse should return something the CLI can show truthfully:current_interval_remaining_percent: 0andcurrent_weekly_remaining_percent: 0(consistent with(0/0 used)), ormodel_name: "video", available_in_plan: false(or an explicitstatus: "not_in_plan") so the CLI can render "video — not in your Token Plan Plus" instead of a misleading "100% remaining".current_interval_total_count === 0 && current_weekly_total_count === 0 && current_interval_status === 3and render the row as0% 剩余 — not in your current plan(or similar) so the user is not sent straight intommx video generateonly to be turned away with 2056.Either way, the user-facing experience should not say "100% remaining" and then "0/0 used" within the same minute for the same plan.
Root cause (hypothesis)
The
/v1/token_plan/remainsresponse is being computed in a way that conflates "no usage so far" with "no allowance at all". For plans where a model is not bundled (Token Plan Plus does not includevideo), the server returns:0(correct: there is no quota bucket)100(wrong: this is computed as100% of 0, not as a real remaining-quota signal)3(a status code whose meaning is undocumented in the public API; "not in plan" is the only interpretation consistent with the generation endpoint's(0/0 used))Meanwhile
/v1/video_generationenforces the real plan:(0/0 used)because the model is not in the plan at all. The two endpoints are not derived from the same source of truth.The fix in #165 made the panel render the percent fields, which now carries this inconsistency straight to the user.
Suggested fix
Option A — server-side (preferred)
Make
/v1/token_plan/remainsand/v1/video_generationagree. Concretely, when a model is not bundled in the user's plan:{ "model_name": "video", "current_interval_total_count": 0, "current_interval_usage_count": 0, "current_weekly_total_count": 0, "current_weekly_usage_count": 0, "current_interval_remaining_percent": 0, "current_weekly_remaining_percent": 0, "current_interval_status": 4, // new: "not_in_plan" "current_weekly_status": 4, "not_in_plan": true }…so the CLI can render
video — 不在当前套餐中/not in your plan, and the user can decide whether to upgrade before re-running the generation call.Option B — CLI-side guardrail (defense in depth, can ship immediately)
In
mmx quota show, whencurrent_interval_total_count === 0 && current_weekly_total_count === 0 && current_interval_status !== 1(the "no bucket" case), render the row as:…regardless of what the
*_remaining_percentfields say. This way the user is never told "100% remaining" for a model they cannot use.Bonus: a preflight check in
mmx video generate— if the quota endpoint reports this "no bucket" state, fail fast with a clear error likevideo generation is not included in your Token Plan Plus. Upgrade your plan at <url>.instead of submitting a task and getting a 2056 back. The current 2056 message is correct, but only the user who reads the raw JSON sees it; the CLI swallows the message into a generic "Task failed" unless--verboseis on.Related
mmx quota show(text mode) displays0 / 0with empty progress bar for time-based Token Plans, ignoringcurrent_interval_remaining_percent#165 —mmx quota show(text mode) displays0 / 0with empty progress bar for time-based Token Plans, ignoringcurrent_interval_remaining_percent(closed in v1.0.16). Same root cause area: the CLI/API pair is conflating count and time-window semantics, and the percent / status / not-in-plan axes are not orthogonal.mmx quota --output jsonfieldcurrent_interval_usage_countshows remaining quota, not usage. Adjacent: same family of "field name vs meaning" mismatches between the server response and the CLI display.Reproduction environment
mmx 1.0.16GET https://api.minimaxi.com/v1/token_plan/remainsPOST https://api.minimaxi.com/v1/video_generationcn, video model =MiniMax-Hailuo-2.3(default)