{"record":{"id":"d06994c166254de7","repo":"apple/pkl","slug":"unexpectedcurlyprobablyamendsexpression-d06994","errorCode":"unexpectedCurlyProbablyAmendsExpression","errorMessage":"Unexpected token: `'{'`.\n\nIf you meant to write an amends expression, wrap the parent in parentheses. Try: `({0}) '{' ... '}'`","messagePattern":"Unexpected token: `'(.+?)\\) '(.+?)'`","errorType":"exception","errorClass":"ParserError","httpStatus":null,"severity":"error","filePath":"pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java","lineNumber":1069,"sourceCode":"  }\n\n  @SuppressWarnings(\"DuplicatedCode\")\n  private Expr parseExprRest(Expr expr) {\n    // non-null\n    if (lookahead == Token.NON_NULL) {\n      var end = next().span;\n      var res = new NonNullExpr(expr, expr.span().endWith(end));\n      return parseExprRest(res);\n    }\n    // amends\n    if (lookahead == Token.LBRACE) {\n      if (expr instanceof ParenthesizedExpr\n          || expr instanceof AmendsExpr\n          || expr instanceof NewExpr) {\n        var body = parseObjectBody();\n        return parseExprRest(new AmendsExpr(expr, body, expr.span().endWith(body.span())));\n      }\n      throw parserError(\"unexpectedCurlyProbablyAmendsExpression\", expr.text(lexer.getSource()));\n    }\n    // qualified access\n    if (lookahead == Token.DOT || lookahead == Token.QDOT) {\n      var isNullable = next().token == Token.QDOT;\n      var identifier = parseIdentifier();\n      ArgumentList argumentList = null;\n      if (lookahead == Token.LPAREN && !precededBySemicolon && _lookahead.newLinesBetween == 0) {\n        argumentList = parseArgumentList();\n      }\n      var lastSpan = argumentList != null ? argumentList.span() : identifier.span();\n      var res =\n          new QualifiedAccessExpr(\n              expr, identifier, isNullable, argumentList, expr.span().endWith(lastSpan));\n      return parseExprRest(res);\n    }\n    // subscript (needs to be in the same line as the expression)\n    if (lookahead == Token.LBRACK && !precededBySemicolon && _lookahead.newLinesBetween == 0) {\n      next();","sourceCodeStart":1051,"sourceCodeEnd":1087,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java#L1051-L1087","documentation":"A `{` followed an expression that cannot be amended implicitly. Only parenthesized expressions, amends expressions, and `new` expressions can take a `{ ... }` body directly; for anything else the parser throws \"Unexpected token: `'{'`\" with a hint to wrap the parent in parentheses to write an amends expression.","triggerScenarios":"Writing `foo.bar { ... }` intending to amend the result; `myExpr { ... }` where `myExpr` is a plain identifier/qualified access; `if (cond) x { ... }` style trailing bodies; amending the result of a function call without parens: `fetch() { ... }`.","commonSituations":"Users expecting trailing-`{}` amend sugar to work on any expression; converting `new Foo { ... }` patterns to computed values; qualified accesses to defaults that should be amended via parentheses.","solutions":["Wrap the base expression in parentheses as the message suggests: `(foo.bar) { ... }`.","If the base is a module-level or imported default, prefer explicit `... { ... }` amends syntax or `new { ... }` for fresh objects.","If `{ ... }` was meant as a block, restructure — Pkl expressions do not take braces except for amends/new.","Check whether you actually wanted object-literal syntax (`new Type { ... }`) rather than amending an arbitrary expression."],"exampleFix":"// before\nx = config.bird { name = \"tweety\" }\n// after\nx = (config.bird) { name = \"tweety\" }","handlingStrategy":"validation","validationCode":"// Only parenthesized/new/amends bases may take a trailing '{ }'\nconst BARE_AMEND = /^\\s*(?!new\\b)(?!\\()[A-Za-z_][\\w.]*\\s*\\{/;\nfunction needsParens(line) { return BARE_AMEND.test(line); }\n// if (needsParens('config.bird { name = \"x\" }')) fix by wrapping base in parens","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Wrap non-new bases in parentheses before a trailing `{ ... }`.","Reserve bare `{ ... }` for `new` and `...` amends contexts.","Configure your editor/linter to flag `ident.path {` patterns."],"tags":["parser","amends","object-body","syntax"],"backgroundTag":"invalid-argument-value","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"}