subframe7536/maple-font · error · TypeError

Invalid class_list, must ends with [@Var, @HexLetter]

Error message

Invalid class_list, must ends with [@Var, @HexLetter]

What it means

generate_fea_string() assembles the font's FEA (feature file) string and relies on the caller-provided class_list ending with exactly the @Var and @HexLetter classes; these two classes are consumed as cls_var and cls_hex_letter for the calt contextual rules. If either trailing class is missing or in the wrong order, the generated substitutions would reference undefined glyph classes, so the library raises TypeError early. It is a precondition on the ordered class list structure, not on individual class contents.

Source

Thrown at source/py/feature/__init__.py:83

        is_italic (bool): Whether to generate italic features
        is_cn (bool): Whether to include Chinese-specific features
        is_normal (bool): Whether to generate normal preset
        is_calt (bool): Whether to enable calt
        variable_enabled_feature_list (list[str]): List of features that
            be enabled in variable format
        infinite (bool): Whether to add infinite arrow ligatures
    """
    print(
        f"Generating feature string with italic={is_italic}, cn={is_cn}, normal={is_normal}, calt={is_calt}, variable={bool(variable_enabled_feature_list)}, infinite={enable_infinite}, tag={enable_tag}"
    )
    infinite_helper.set(enable_infinite)

    class_list = class_list_italic if is_italic else class_list_regular
    cv_list = cv_list_italic(True) if is_italic else cv_list_regular(True)
    ss_list = ss_list_italic(True) if is_italic else ss_list_regular(True)

    if class_list[-2].name != "Var" or class_list[-1].name != "HexLetter":
        raise TypeError("Invalid class_list, must ends with [@Var, @HexLetter]")

    calt_feat = get_calt(
        cls_var=class_list[-2],
        cls_hex_letter=class_list[-1],
        is_italic=is_italic,
        is_normal=is_normal,
        enable_tag=enable_tag,
        remove_italic_calt=remove_italic_calt,
    )

    # clear calt for no ligature
    if not is_calt:
        calt_feat.content = []

    cv_ss_list = deepcopy(cv_list + (cv_list_cn if is_cn else []) + ss_list)

    # for variable font, freeze feature by moving it to `calt`
    if variable_enabled_feature_list:

View on GitHub (pinned to c08fda97fe)

Solutions

  1. Append the Var and HexLetter classes to the end of your class_list: class_list = class_list + [cls_var, cls_hex_letter].
  2. Ensure the order is [... , @Var, @HexLetter] — Var second-to-last, HexLetter last.
  3. Prefer using the library's class_list_italic or class_list_regular builders (or copy/extend them) instead of hand-assembling the list.
  4. Verify class names with [c.name for c in class_list[-2:]] == ['Var', 'HexLetter'] before calling.

Example fix

// before
class_list = my_custom_classes
generate_fea_string(class_list, ...)
// after
class_list = my_custom_classes + [cls_var, cls_hex_letter]
assert class_list[-2].name == 'Var' and class_list[-1].name == 'HexLetter'
generate_fea_string(class_list, ...)
Defensive patterns

Strategy: validation

Validate before calling

def validate_class_list(class_list):
    if len(class_list) < 2 or class_list[-2].name != 'Var' or class_list[-1].name != 'HexLetter':
        raise ValueError('class_list must end with [@Var, @HexLetter]')

validate_class_list(class_list)
generate_fea_string(class_list, ...)

Type guard

def ends_with_var_hexletter(class_list) -> bool:
    return len(class_list) >= 2 and class_list[-2].name == 'Var' and class_list[-1].name == 'HexLetter'

Try / catch

try:
    fea = generate_fea_string(class_list, is_italic=is_italic)
except TypeError as e:
    if 'must ends with' in str(e):
        class_list = class_list + [cls_var, cls_hex_letter]
        fea = generate_fea_string(class_list, is_italic=is_italic)
    else:
        raise

Prevention

When it happens

Trigger: Calling generate_fea_string(class_list=...) where class_list[-2].name != 'Var' or class_list[-1].name != 'HexLetter' — e.g. passing a list built without those classes, in a different order, or with custom class lists missing them.

Common situations: Building a custom class_list for a custom font variant and forgetting to append cls_var and cls_hex_letter; reordering classes; copying an older class_list from a version before Var/HexLetter classes were introduced.

Related errors


AI-assisted analysis of subframe7536/maple-font@c08fda97fe (2026-08-28). Data as JSON: /api/errors/9f03fd1c9120783d. Report an issue: GitHub.