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() raises FalError when the requested (slot, tier) pair does not exist in the TIERS registry — either the slot name is unknown (TIERS.get(slot) is None) or the tier name is not a key in that slot's table. The message helpfully lists the available tier names for the given slot. This guards endpoint repointing against typos and stale tier names.
Solutions
- Read the available tiers from the error message and use one of those exact names
- Check TIERS (or the module's documented slot/tier table) for the correct slot name first
- Print sorted(TIERS) to enumerate valid slots before calling use_tier
- Update code after library upgrades where tier names may have been renamed
Example fix
// before
use_tier("image", "quality") # tier 'quality' doesn't exist
// after
from taste import falapi
print(sorted(falapi.TIERS["image"])) # e.g. ['fast', 'pro']
falapi.use_tier("image", "pro") Defensive patterns
Strategy: validation
Validate before calling
from taste import falapi
def safe_use_tier(slot, tier):
if slot not in falapi.TIERS:
raise ValueError(f"unknown slot '{slot}'; have {sorted(falapi.TIERS)}")
if tier not in falapi.TIERS[slot]:
raise ValueError(f"slot '{slot}' has tiers {sorted(falapi.TIERS[slot])}")
return falapi.use_tier(slot, tier) Type guard
def tier_exists(slot: str, tier: str) -> bool:
table = falapi.TIERS.get(slot)
return bool(table) and tier in table Try / catch
try:
falapi.use_tier(slot, tier)
except falapi.FalError as e:
print(e) # message lists valid tiers for the slot
raise Prevention
- Inspect TIERS at startup and validate slot/tier names against it
- Reference tier names via constants or TIERS keys rather than string literals
- Re-check tier names after library upgrades (renames are common)
- Keep slot/tier choices in one config location to avoid drift
When it happens
Trigger: Calling use_tier('video', 'pro') when slot 'video' doesn't exist in TIERS, or when the tier string is misspelled/renamed, or when checking a tier against the wrong slot.
Common situations: Typos in slot or tier names; using tier names from an older version of the library after a rename; assuming tiers are shared across slots when each slot defines its own set; copying a use_tier call from code targeting a different slot.
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
- ECC_PROJECT_DIR must be a child path within /workspace.
- Announcements discussion category is required
- Choose at least one guided harness: Claude, Codex, or Kimi.
- config must be a JSON object
- createPlanCanvasServer requires a session store
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/1761b99c73ee0bc1.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/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)