reflex-dev/reflex · error · TypeError

f"Icon name must be a string, got {tag_var._var_type}"

Error message

f"Icon name must be a string, got {tag_var._var_type}"

What it means

When `tag` is a runtime Var (not a literal), Reflex guesses its type to decide whether a DynamicIcon can be rendered. If the Var's inferred type is not a string (int, bool, list, etc.), TypeError is raised because the client cannot look up an icon by a non-string name.

Source

Thrown at packages/reflex-components-lucide/src/reflex_components_lucide/icon.py:75

            else:
                msg = f"Passing multiple children to Icon component is not allowed: remove positional arguments {children[1:]} to fix"
                raise AttributeError(msg)
        if "tag" not in props:
            msg = "Missing 'tag' keyword-argument for Icon"
            raise AttributeError(msg)

        tag_var: Var | LiteralVar = Var.create(props.pop("tag"))
        if isinstance(tag_var, LiteralVar):
            if isinstance(tag_var, LiteralStringVar):
                tag = format.to_snake_case(tag_var._var_value.lower())
            else:
                msg = f"Icon name must be a string, got {type(tag_var)}"
                raise TypeError(msg)
        elif isinstance(tag_var, Var):
            tag_stringified = tag_var.guess_type()
            if not isinstance(tag_stringified, StringVar):
                msg = f"Icon name must be a string, got {tag_var._var_type}"
                raise TypeError(msg)
            return DynamicIcon.create(name=tag_stringified.replace("_", "-"), **props)

        if tag not in LUCIDE_ICON_LIST:
            icons_sorted = sorted(
                LUCIDE_ICON_LIST,
                key=lambda s, tag=tag: format.length_of_largest_common_substring(
                    tag, s
                ),
                reverse=True,
            )
            logger.warning(
                f"Invalid icon tag: {tag}. Please use one of the following: {', '.join(icons_sorted[0:10])}, ..."
                "\nSee full list at https://reflex.dev/docs/library/data-display/icon/#icons-list. Using 'circle_help' icon instead."
            )
            tag = "circle_help"

        props["tag"] = LUCIDE_ICON_MAPPING_OVERRIDE.get(tag, format.to_title_case(tag))
        props["alias"] = f"Lucide{props['tag']}"

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Type the state field as str: icon_name: str = 'home', then rx.icon(tag=State.icon_name)
  2. Convert ints to names server-side (in an event handler) before assigning to the icon state field

Example fix

# before
class S(rx.State):
    icon: int = 0
rx.icon(tag=S.icon)
# after
class S(rx.State):
    icon: str = 'home'
rx.icon(tag=S.icon)
Defensive patterns

Strategy: type-guard

Validate before calling

# ensure the state field is str-typed
class State(rx.State):
    icon_name: str = 'home'

Type guard

def icon_var_is_str(var) -> bool:
    return var._var_type is str or issubclass(var._var_type, str)

Prevention

When it happens

Trigger: rx.icon(tag=State.count) with count: int, or a Var whose _var_type is not str (e.g. an object or number field).

Common situations: Storing icon selection as an index/enum int in state instead of the icon name string.

Related errors


AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28). Data as JSON: /api/errors/f6e000bc50c56aa4. Report an issue: GitHub.