subframe7536/maple-font · error · TypeError

id should > 0 and < 20 in Stylistic Sets, current is {id}

Error message

id should > 0 and < 20 in Stylistic Sets, current is {id}

What it means

Stylistic Sets (ssXX) OpenType features use ids 1–20, formatted as tags ss01–ss20; the OpenType ss tag space for this library ends at ss20. The Stylistic Sets feature __init__ validates `1 <= id <= 20` and raises TypeError otherwise. Like the cv validation, this fires at object construction time before any FEA is generated.

Source

Thrown at source/py/feature/ast.py:167

            Line("FeatUILabelNameID {", 1),
            Line(f'name "{self.tag.upper()}: {_name}";', 2),
            Line("};", 1),
            Line("};"),
            Line(""),
        ]


class StylisticSet(FeatureWithDocs):
    def __init__(
        self,
        id: int,
        desc: str,
        content: Clazz | Lookup | Line | list,
        version: str,
        example: str,
    ):
        if id < 1 or id > 20:
            raise TypeError(
                f"id should > 0 and < 20 in Stylistic Sets, current is {id}"
            )

        FeatureWithDocs.__init__(
            self,
            id=id,
            tag=f"ss{id:02d}",
            desc=desc,
            content=content,
            version=version,
            example=example,
        )

    def get_name_lines(self) -> list[Line]:
        _name = re.sub(REGEXP, "", self.desc.replace("`", " ")).strip()
        return [
            Line("featureNames {"),
            Line(f'name "{self.tag.upper()}: {_name}";', 1),

View on GitHub (pinned to c08fda97fe)

Solutions

  1. Set the stylistic set id to an integer in the range 1–20.
  2. Merge sets beyond 20 into existing ss ids, since OpenType ss tags stop at ss20.
  3. Validate ids from config/CLI input before constructing the feature object.

Example fix

// before
StylisticSets(id=21, desc='...', content=..., version='1.0', example='...')
// after
id = 21
if not 1 <= id <= 20:
    id = 20  # merge or remap
StylisticSets(id=id, desc='...', content=..., version='1.0', example='...')
Defensive patterns

Strategy: validation

Validate before calling

def check_ss_id(id):
    if not isinstance(id, int) or not (1 <= id <= 20):
        raise ValueError(f'ss id must be int 1-20, got {id}')

check_ss_id(id)
feature = StylisticSets(id=id, ...)

Type guard

def is_valid_ss_id(id) -> bool:
    return isinstance(id, int) and 1 <= id <= 20

Try / catch

try:
    feature = StylisticSets(id=id, desc=desc, content=content, version=version, example=example)
except TypeError as e:
    if 'Stylistic Sets' in str(e):
        logging.error(f'remap ss id {id} into 1-20')
        id = min(max(int(id), 1), 20)
        feature = StylisticSets(id=id, desc=desc, content=content, version=version, example=example)
    else:
        raise

Prevention

When it happens

Trigger: Constructing a Stylistic Sets feature with id=0, negative id, or id >= 21, e.g. ss_list builders fed ids from an unbounded enumeration.

Common situations: Trying to define ss21+ for extra stylistic variants; zero-based indices from config; iterating over a list of desired sets with an off-by-one that produces id 0.

Related errors


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