{"record":{"id":"c44e81178ee18cc2","repo":"subframe7536/maple-font","slug":"id-should-0-and-20-in-stylistic-sets-current","errorCode":null,"errorMessage":"id should > 0 and < 20 in Stylistic Sets, current is {id}","messagePattern":"id should > 0 and < 20 in Stylistic Sets, current is (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"source/py/feature/ast.py","lineNumber":167,"sourceCode":"            Line(\"FeatUILabelNameID {\", 1),\n            Line(f'name \"{self.tag.upper()}: {_name}\";', 2),\n            Line(\"};\", 1),\n            Line(\"};\"),\n            Line(\"\"),\n        ]\n\n\nclass StylisticSet(FeatureWithDocs):\n    def __init__(\n        self,\n        id: int,\n        desc: str,\n        content: Clazz | Lookup | Line | list,\n        version: str,\n        example: str,\n    ):\n        if id < 1 or id > 20:\n            raise TypeError(\n                f\"id should > 0 and < 20 in Stylistic Sets, current is {id}\"\n            )\n\n        FeatureWithDocs.__init__(\n            self,\n            id=id,\n            tag=f\"ss{id:02d}\",\n            desc=desc,\n            content=content,\n            version=version,\n            example=example,\n        )\n\n    def get_name_lines(self) -> list[Line]:\n        _name = re.sub(REGEXP, \"\", self.desc.replace(\"`\", \" \")).strip()\n        return [\n            Line(\"featureNames {\"),\n            Line(f'name \"{self.tag.upper()}: {_name}\";', 1),","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/subframe7536/maple-font/blob/c08fda97fef73d68c1755219852150770f6e6578/source/py/feature/ast.py#L149-L185","documentation":"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.","triggerScenarios":"Constructing a Stylistic Sets feature with id=0, negative id, or id >= 21, e.g. ss_list builders fed ids from an unbounded enumeration.","commonSituations":"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.","solutions":["Set the stylistic set id to an integer in the range 1–20.","Merge sets beyond 20 into existing ss ids, since OpenType ss tags stop at ss20.","Validate ids from config/CLI input before constructing the feature object."],"exampleFix":"// before\nStylisticSets(id=21, desc='...', content=..., version='1.0', example='...')\n// after\nid = 21\nif not 1 <= id <= 20:\n    id = 20  # merge or remap\nStylisticSets(id=id, desc='...', content=..., version='1.0', example='...')","handlingStrategy":"validation","validationCode":"def check_ss_id(id):\n    if not isinstance(id, int) or not (1 <= id <= 20):\n        raise ValueError(f'ss id must be int 1-20, got {id}')\n\ncheck_ss_id(id)\nfeature = StylisticSets(id=id, ...)","typeGuard":"def is_valid_ss_id(id) -> bool:\n    return isinstance(id, int) and 1 <= id <= 20","tryCatchPattern":"try:\n    feature = StylisticSets(id=id, desc=desc, content=content, version=version, example=example)\nexcept TypeError as e:\n    if 'Stylistic Sets' in str(e):\n        logging.error(f'remap ss id {id} into 1-20')\n        id = min(max(int(id), 1), 20)\n        feature = StylisticSets(id=id, desc=desc, content=content, version=version, example=example)\n    else:\n        raise","preventionTips":["OpenType ss tags stop at ss20 — consolidate extra sets into existing ids.","Never feed zero-based indices directly into ss ids.","Centralize id assignment in one validated factory function."],"tags":["python","typeerror","range-validation","stylistic-sets","opentype-features"],"backgroundTag":"id-out-of-range","analyzedSha":"c08fda97fef73d68c1755219852150770f6e6578","analyzedAt":"2026-08-28T22:07:29.503Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}