twigphp/Twig · error · LogicException

Token of type " " does not exist.

Error message

Token of type "%s" does not exist.

What it means

Token::typeToString() converts a numeric token type constant (e.g. Token::NAME_TYPE) into its human-readable name. If the integer does not correspond to any defined Twig token type, the default branch throws this LogicException. It is called from __toString() and error message formatting, so it usually surfaces while rendering diagnostics for a corrupt token.

Solutions

  1. Only pass constants from Twig\Token (NAME_TYPE, NUMBER_TYPE, etc.) to typeToString()/new Token().
  2. Add an is_int + range/constant check before constructing tokens from external input.
  3. If writing a custom lexer, verify every type value against Token's defined constants.
  4. Check the call site in __toString()/error formatting for a corrupted token that originates earlier in the lexer.

Example fix

// before
$token = new Token($userData['type'], $value, 1); // type may be arbitrary

// after
$known = [\Twig\Token::NAME_TYPE, \Twig\Token::NUMBER_TYPE, \Twig\Token::STRING_TYPE, /* ... */];
if (!in_array($userData['type'], $known, true)) {
    throw new \InvalidArgumentException('Unknown token type');
}
$token = new Token((int) $userData['type'], $value, 1);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!in_array($type, [\Twig\Token::BLOCK_END_TYPE, \Twig\Token::NAME_TYPE, /* all used constants */], true)) {
    throw new \InvalidArgumentException('Unknown token type: '.$type);
}

Type guard

function isValidTokenType(int $type): bool
{
    return in_array($type, (new ReflectionClass(\Twig\Token::class))->getConstants(), true);
}

Try / catch

try { $label = \Twig\Token::typeToString($type); } catch (\LogicException $e) { if (str_contains($e->getMessage(), 'does not exist')) { $label = 'UNKNOWN_TYPE('.$type.')'; } else { throw $e; } }

Prevention

When it happens

Trigger: Passing an integer to Token::typeToString() (or to a Token whose ->type is such an int) that is not one of the Token::*_TYPE constants — e.g. hand-constructed Token objects with bogus types, lexer bugs, or int-cast garbage from custom lexers.

Common situations: Custom lexer/TokenParser producing tokens with out-of-range types; passing a raw value (e.g. from untrusted data) to Token::typeToString(); debugging a syntax error where the token stream was built incorrectly.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/e78b5cc54e977b38. Report an issue: GitHub.

Appendix: source

Thrown at src/Token.php:219

                $name = 'OPERATOR_TYPE';
                break;
            case self::PUNCTUATION_TYPE:
                $name = 'PUNCTUATION_TYPE';
                break;
            case self::INTERPOLATION_START_TYPE:
                $name = 'INTERPOLATION_START_TYPE';
                break;
            case self::INTERPOLATION_END_TYPE:
                $name = 'INTERPOLATION_END_TYPE';
                break;
            case self::ARROW_TYPE:
                $name = 'ARROW_TYPE';
                break;
            case self::SPREAD_TYPE:
                $name = 'SPREAD_TYPE';
                break;
            default:
                throw new \LogicException(\sprintf('Token of type "%s" does not exist.', $type));
        }

        return $short ? $name : 'Twig\Token::'.$name;
    }

    public static function typeToEnglish(int $type): string
    {
        switch ($type) {
            case self::EOF_TYPE:
                return 'end of template';
            case self::TEXT_TYPE:
                return 'text';
            case self::BLOCK_START_TYPE:
                return 'begin of statement block';
            case self::VAR_START_TYPE:
                return 'begin of print statement';
            case self::BLOCK_END_TYPE:
                return 'end of statement block';

View on GitHub (pinned to a414c3a491)