subframe7536/maple-font · error · ValueError

Last letter of `target` must in {list(__map.keys())}, curren

Error message

Last letter of `target` must in {list(__map.keys())}, current is '{target[-1]}'

What it means

In tag_custom(), the final character of each target pattern must be one of the closing/sharp bracket glyphs mapped in __map: '<', '>', '(', ')', '[', ']'. These map to the start/end glyph classes used to build the substitution chain. If target[-1] is anything else (letter, underscore, digit, punctuation like '!'), ValueError is raised. Note target[-1] also implies an empty target would raise IndexError first, so targets must be non-empty too.

Source

Thrown at source/py/feature/calt/tag.py:165

            class definitions
    Returns:
        ast.Lookup: A Lookup object containing the substitution rules, named with pattern
            "custom_tag_{target middle chars}".
    Example:
        >>> tag_custom("_TODO_", "(TODO)")
    """
    result = []
    for source, target in content_list:
        glyphs = list(source)
        glyphs_len = len(glyphs)
        target_len = len(target)

        if target_len != glyphs_len:
            raise ValueError(
                f"length of `content` ({glyphs_len}) must be equal to length of `target` ({target_len})."
            )
        if target[-1] not in __map:
            raise ValueError(
                f"Last letter of `target` must in {list(__map.keys())}, current is '{target[-1]}'"
            )

        # Parse source
        source_list = []
        for g in glyphs:
            if g.isalpha():
                source_list.append(f"@{g.upper()}")
            else:
                source_list.append(ast.gly(g))

        # Parse target
        target_list = []
        for target_gly in target:
            if target_gly in __map:
                target_list.append(f"{__map[target_gly]}.bg")
            elif target_gly.isalpha():
                up = target_gly.upper()

View on GitHub (pinned to c08fda97fe)

Solutions

  1. End the target with one of < > ( ) [ ] — e.g. '(TODO)', '[DEBUG]', '<WARN>'.
  2. Add the missing closing bracket character to the target string.
  3. If you need a new terminator style, extend the __map dict in source/py/feature/calt/tag.py:123.
  4. Pre-validate: `assert target and target[-1] in '<>()[]'` before calling.

Example fix

// before
tag_custom([('_TODO_', 'TODO')], bg_cls_dict)
// after
tag_custom([('_TODO_', '(TODO)')], bg_cls_dict)
Defensive patterns

Strategy: validation

Validate before calling

VALID_TERMINATORS = '<>()[]'
def validate_target(tgt):
    if not tgt or tgt[-1] not in VALID_TERMINATORS:
        raise ValueError(f'target {tgt!r} must end with one of {VALID_TERMINATORS}')

for _, tgt in content_list:
    validate_target(tgt)
tag_custom(content_list, bg_cls_dict)

Type guard

def has_valid_terminator(tgt: str) -> bool:
    return bool(tgt) and tgt[-1] in '<>()[]'

Try / catch

try:
    lookup = tag_custom(content_list, bg_cls_dict)
except ValueError as e:
    if 'Last letter of `target`' in str(e):
        content_list = [(s, t + ')') for s, t in content_list if not has_valid_terminator(t)]
        lookup = tag_custom(content_list, bg_cls_dict)
    else:
        raise

Prevention

When it happens

Trigger: Calling tag_custom with a target whose last character is not in ['<','>','(',')','[',']'], e.g. ('_TODO_', 'TODO!') or ('__', '_DONE_') ending in underscore.

Common situations: Forgetting the closing bracket of the visual tag design; using ASCII-only tags without decorative brackets; generating targets programmatically and dropping the final bracket character.

Related errors


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