Textualize/textual · error · ValueError

Template must contain at least one non-separator character

Error message

Template must contain at least one non-separator character

What it means

A ValueError raised in MaskedInput.__init__ (via _Template construction) when every character slot in the template is a separator — i.e. there is no position for user input. A mask like '--' or '//' with only separator characters cannot hold a value, so construction fails.

Source

Thrown at src/textual/widgets/_masked_input.py:141

                    char_definition = self.CharDefinition(
                        re.compile(pattern), char_flags
                    )
                else:
                    char_definition = self.CharDefinition(
                        re.compile(re.escape(char)), _CharFlags.SEPARATOR, char
                    )

            char_definition.flags |= flags
            self.template.append(char_definition)

        if template_chars:
            self.blank = template_chars[0]

        if all(
            (_CharFlags.SEPARATOR in char_definition.flags)
            for char_definition in self.template
        ):
            raise ValueError(
                "Template must contain at least one non-separator character"
            )

        self.update_mask(input.placeholder)

    def validate(self, value: str) -> ValidationResult:
        """Checks if `value` matches this template, always returning a ValidationResult.

        Args:
            value: The string value to be validated.

        Returns:
            A ValidationResult with the validation outcome.

        """
        if self.check(value.ljust(len(self.template), chr(0)), False):
            return self.success()
        else:

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Ensure the template contains at least one input character (e.g. '9999-9999', not '-----').
  2. Validate user-supplied templates before constructing MaskedInput (check for at least one non-separator slot).
  3. Provide a sensible default template when validation fails.
  4. Consult MaskedInput docs for valid template characters (1, a, A, 9, *, etc.).

Example fix

# before
field = MaskedInput(template=cfg['mask'])  # cfg['mask'] == '--'

# after
mask = cfg['mask'] if any(c in '1aA9*@#' for c in cfg['mask']) else '999-9999'
field = MaskedInput(template=mask)
Defensive patterns

Strategy: validation

Validate before calling

INPUT_CHARS = set('1aA9*@#')
assert any(c in INPUT_CHARS for c in template), 'mask has no input slots'
MaskedInput(template=template)

Try / catch

try:
    field = MaskedInput(template=mask)
except ValueError:
    field = MaskedInput(template='999-9999')  # fallback mask

Prevention

When it happens

Trigger: Passing a template consisting solely of separator characters (e.g. MaskedInput(template='///')); a template built dynamically from config where all input slots were dropped; templates like '()' where every char is a literal separator.

Common situations: Config-driven masks for phone/date formats where a malformed pattern slips through; building templates by string concatenation that accidentally removes all input slots; typos using a wrong mask character for every slot.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/576f3fa86fba9a95. Report an issue: GitHub.