affaan-m/ECC · error · FalError
no tier ' ' for slot ' '; have
Error message
no tier '{tier}' for slot '{slot}'; have {sorted(table) if table else 'no tiers'} What it means
use_tier() repoints a model slot (e.g. 'image', 'video') at a named tier by looking up TIERS[slot][tier]. It raises falapi.FalError when the slot has no tier table or the tier name is absent from it, listing the valid tiers in the message. ENDPOINTS is only mutated on success.
Solutions
- Use one of the valid tiers listed in the message (sorted table contents) — e.g. use_tier('image', 'fast').
- Print TIERS (or inspect falapi.py) to see available slots and tier names before switching.
- Fix typos/casing in the tier or slot string; names are matched exactly.
- If a tier was renamed after an upgrade, update call sites/config to the new tier name.
- Wrap in try/except falapi.FalError to fall back to a default tier instead of failing.
Example fix
// before
falapi.use_tier("video", "pro") # FalError: no tier 'pro'
// after
try:
falapi.use_tier("video", "quality")
except falapi.FalError as exc:
print(exc) # shows valid tiers; keep default endpoint Defensive patterns
Strategy: validation
Validate before calling
from taste import falapi
slot_tiers = falapi.TIERS.get("video", {})
if tier not in slot_tiers:
raise SystemExit(f"tier '{tier}' not in {sorted(slot_tiers)}") Type guard
def tier_exists(slot: str, tier: str) -> bool:
return tier in falapi.TIERS.get(slot, {}) Try / catch
try:
falapi.use_tier(slot, tier)
except falapi.FalError as exc:
log.warning("tier switch failed, keeping default: %s", exc) Prevention
- Inspect TIERS to list valid slots/tiers before switching
- Copy tier names exactly (case-sensitive) from the message or source
- Check for renames after upgrading the library
- Wrap tier switches in try/except FalError with a sane default
- Centralize tier names as constants instead of inline strings
When it happens
Trigger: use_tier(slot, tier) called with a slot key not present in TIERS, or a tier string that doesn't match any key in that slot's table — e.g. use_tier('video', 'pro') when the video slot defines only {'fast': ..., 'quality': ...}.
Common situations: Tier name typo or wrong casing; tier renamed in a newer version of the library while scripts/config still use the old name; slot name typo ('vedio'); docs example using a tier this install doesn't define.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid format: . Use text or json.
- live transport requires TASTE_FORGE_ALLOW_LIVE=1
- replay.bad_mode
- unknown role " "; expected one of
- Announcements discussion category is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/91080c78a5d345b0.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-distillation/scripts/taste/falapi.py:117
},
"text_to_3d": {
"best": "fal-ai/hunyuan-3d/v3.1/pro/text-to-3d",
"fast": "fal-ai/hunyuan-3d/v3.1/rapid/text-to-3d",
"value": "tripo3d/h3.1/text-to-3d",
},
"text_to_image": {
"best": "fal-ai/nano-banana-pro", # $0.15 flat, strongest identity
"value": "fal-ai/flux-2-pro", # $0.03 first MP
"instruct": "openai/gpt-image-2", # best typography / instructions
},
}
def use_tier(slot: str, tier: str) -> str:
"""Repoint one slot at a named tier. Returns the endpoint now in use."""
table = TIERS.get(slot)
if not table or tier not in table:
raise FalError(
f"no tier '{tier}' for slot '{slot}'; "
f"have {sorted(table) if table else 'no tiers'}"
)
ENDPOINTS[slot] = table[tier]
return ENDPOINTS[slot]
# fal has NO endpoint that renders a mesh to images or video. The catalogue
# splits 3D into image-to-3d, text-to-3d and 3d-to-3d, and every member of
# 3d-to-3d emits another mesh - there is no 3d-to-image or 3d-to-video
# category at all. So a minted GLB cannot re-enter the video graph on fal.
#
# It can re-enter locally: render a turntable here (taste/render3d.py), then
# either assemble the frames with local ffmpeg or push them through
# ``images_to_video`` above. That is why the 3D branch is not a dead end even
# though the platform has no renderer.
NO_RENDER_ENDPOINT = True
View on GitHub (pinned to 8321021c54)