{"record":{"id":"8414c1e816b4e840","repo":"apple/pkl","slug":"stringindentationmustmatchlastline-8414c1","errorCode":"stringIndentationMustMatchLastLine","errorMessage":"Line must match or exceed indentation of the String's last line.","messagePattern":"Line must match or exceed indentation of the String's last line\\.","errorType":"exception","errorClass":"GenericParserError","httpStatus":null,"severity":"error","filePath":"pkl-parser/src/main/java/org/pkl/parser/GenericParserImpl.java","lineNumber":1064,"sourceCode":"    if (beforeLast.type == NodeType.STRING_NEWLINE) return;\n    var text = beforeLast.text(lexer.getSource());\n    if (!text.isBlank()) {\n      throw parserError(\n          ErrorMessages.create(\"closingStringDelimiterMustBeginOnNewLine\"), beforeLast.span);\n    }\n  }\n\n  private void validateStringIndentation(List<Node> nodes) {\n    var indentNode = nodes.get(nodes.size() - 2);\n    if (indentNode.type == NodeType.STRING_NEWLINE) return;\n    var indent = indentNode.text(lexer.getSource());\n    var previousNewline = false;\n    for (var i = 1; i < nodes.size() - 2; i++) {\n      var child = nodes.get(i);\n      if (child.type != NodeType.STRING_NEWLINE && previousNewline) {\n        var text = child.text(lexer.getSource());\n        if (!text.startsWith(indent)) {\n          throw parserError(ErrorMessages.create(\"stringIndentationMustMatchLastLine\"), child.span);\n        }\n      }\n      previousNewline =\n          child.type == NodeType.STRING_NEWLINE || child.type == NodeType.STRING_CONTINUATION;\n    }\n  }\n\n  private Node parseParenthesizedExpr() {\n    var children = new ArrayList<Node>();\n    expect(Token.LPAREN, children, \"unexpectedToken\", \"(\");\n    if (lookahead() == Token.RPAREN) {\n      ff(children);\n      children.add(makeTerminal(next()));\n      return new Node(NodeType.PARENTHESIZED_EXPR, children);\n    }\n    var elements = new ArrayList<Node>();\n    ff(elements);\n    elements.add(parseExpr(\")\"));","sourceCodeStart":1046,"sourceCodeEnd":1082,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-parser/src/main/java/org/pkl/parser/GenericParserImpl.java#L1046-L1082","documentation":"In a multi-line string, every line after the first must be indented at least as much as the closing delimiter's line, so Pkl knows how much common indentation to strip. validateStringIndentation computes the closer's indent and throws stringIndentationMustMatchLastLine for any line that starts with less indentation.","triggerScenarios":"A line inside a `\"\"\"...\"\"\"` block is dedented relative to the closing delimiter's indentation — e.g. the closer is indented two spaces but one content line starts at column 0.","commonSituations":"Copy-pasting text with varying indentation into a multi-line string; editors auto-dedenting blank-ish lines; mixed tabs/spaces reducing effective indent; generated files with inconsistent indentation.","solutions":["Indent every content line of the string to at least the closing `\"\"\"`'s indentation.","Use consistent indentation (spaces, not mixed tabs) throughout the block.","Dedent pasted text uniformly first, then re-indent the whole block together.","Keep the closing `\"\"\"` at the lowest indentation of the block and indent content lines beyond it."],"exampleFix":"// before\nsql = \"\"\"\n    SELECT 1\nFROM t\n    \"\"\"\n\n// after\nsql = \"\"\"\n    SELECT 1\n    FROM t\n    \"\"\"","handlingStrategy":"validation","validationCode":"// Every content line must be indented >= the closing \"\"\" line's indent\nfunction stringIndentationOk(block) {\n  const lines = block.split('\\n');\n  const closerIndent = lines[lines.length - 1].match(/^\\s*/)[0].length;\n  return lines.slice(1, -1).every(l => l.trim() === '' || l.match(/^\\s*/)[0].length >= closerIndent);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use spaces only — never mix tabs and spaces inside multi-line strings.","Paste text, then select the whole block and re-indent uniformly in one edit.","Place the closing `\"\"\"` at the least-indented column of the block and indent content lines more."],"tags":["pkl","parser","syntax-error","indentation"],"backgroundTag":"invalid-argument-format","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}