{"record":{"id":"e1d655d418dbd34c","repo":"apple/pkl","slug":"invalidcharacter","errorCode":"invalidCharacter","errorMessage":"Invalid identifier `{0}`.","messagePattern":"Invalid identifier `(.+?)`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkl-parser/src/main/java/org/pkl/parser/Lexer.java","lineNumber":263,"sourceCode":"      case '`' -> {\n        lexQuotedIdentifier();\n        yield Token.IDENTIFIER;\n      }\n      case '/' -> lexSlash();\n      case '\"' -> lexStringStart(0);\n      case '#' -> {\n        if (lookahead == '!') {\n          yield lexShebang();\n        } else {\n          yield lexStringStartPounds();\n        }\n      }\n      default -> {\n        if (Character.isDigit(ch)) {\n          yield lexNumber(ch);\n        } else if (isIdentifierStart(ch)) {\n          yield lexIdentifier();\n        } else throw lexError(ErrorMessages.create(\"invalidCharacter\", (char) ch), cursor - 1, 1);\n      }\n    };\n  }\n\n  private Token nextString() {\n    var scope = interpolationStack.getFirst();\n    if (stringEnded) {\n      lexStringEnd(scope);\n      stringEnded = false;\n      interpolationStack.pop();\n      state = State.DEFAULT;\n      return Token.STRING_END;\n    }\n    if (lookahead == EOF) return Token.EOF;\n    if (isEscape) {\n      isEscape = false;\n      // consume the `\\#*`\n      for (var i = 0; i < scope.pounds + 1; i++) {","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-parser/src/main/java/org/pkl/parser/Lexer.java#L245-L281","documentation":"The lexer's default branch cannot classify the character: it is not a digit and not a valid identifier start, so it reports \"Invalid identifier\" with the offending character via lexError keyed as invalidCharacter. This covers stray punctuation, unicode look-alikes, and control characters in Pkl source.","triggerScenarios":"A character that can't start a token appears in code — e.g. `@` outside annotations, `#` outside custom string delimiters, smart quotes from a word processor (`“` instead of `\"`), non-breaking spaces, or emoji in unquoted positions.","commonSituations":"Copying code from docs/slack that converted quotes to smart quotes; invisible BOM or non-breaking space characters; writing DSL-like syntax from another language; stray comment markers.","solutions":["Replace the offending character with its ASCII equivalent (straight quotes, regular spaces).","Quote the text as a string literal if it is data, not code.","Re-save the file as clean UTF-8 without BOM; strip invisible characters.","Check for language-specific syntax (e.g. decorators `@`) that Pkl does not support in that position."],"exampleFix":"// before (smart quotes)\nname = “pkl”\n\n// after\nname = \"pkl\"","handlingStrategy":"validation","validationCode":"function findNonAsciiCodeChars(src) {\n  const issues = [];\n  const lines = src.split(\"\\n\");\n  lines.forEach((line, i) => {\n    const cleaned = line.replace(/\"[^\"]*\"/g, \"\"); // ignore string contents\n    const bad = cleaned.match(/[^\\x20-\\x7E\\t]/g);\n    if (bad) issues.push({ line: i + 1, chars: bad.map(c => c.codePointAt(0).toString(16)) });\n  });\n  return issues;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure editors to insert straight quotes and flag smart quotes in code files.","Save as UTF-8 without BOM; strip non-breaking spaces on paste.","Pre-commit hook running a lexer check (pkl eval) on all .pkl files."],"tags":["lexer","syntax-error","invalid-character","unicode"],"backgroundTag":"invalid-characters","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}