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

  1. Use one of the valid tiers listed in the message (sorted table contents) — e.g. use_tier('image', 'fast').
  2. Print TIERS (or inspect falapi.py) to see available slots and tier names before switching.
  3. Fix typos/casing in the tier or slot string; names are matched exactly.
  4. If a tier was renamed after an upgrade, update call sites/config to the new tier name.
  5. 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

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


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)