apple/pkl · error · ParserError

interpolationInConstant

interpolationInConstant

Error message

String constant cannot have interpolated values.

What it means

The Pkl parser throws this when a string constant (e.g. a module/property name such as `foo` in backticks-less plain constant strings) contains an interpolation sequence (`\(...)`) which is only allowed in string literals, not in string constants used as identifiers. The lexer delivers an INTERPOLATION_START token inside the constant string and the parser rejects it.

Solutions

  1. Remove the `\(...)` interpolation and write the fully expanded string constant literally
  2. Compute the name in Pkl code instead (e.g. build the string as a value and use a computed property / dynamic object key if the grammar allows)
  3. If the target API requires an identifier, generate the source text with a script rather than interpolating in the constant

Example fix

// before
foo\(bar) = 1   // string constant with interpolation
// after
foobar = 1      // or compute the name in a dynamic object
Defensive patterns

Strategy: validation

Validate before calling

// before invoking the parser, reject interpolations in constant strings
const INTERP = /\\\(/;
function assertConstantString(s) {
  if (INTERP.test(s)) throw new Error(`String constant cannot have interpolated values: ${s}`);
}

Type guard

function isConstantString(tok) {
  return typeof tok === 'string' && !tok.includes('\\(');
}

Try / catch

try {
  parser.parseModule(source);
} catch (e) {
  if (e.code === 'interpolationInConstant') {
    console.error(`Replace \\(...) in the string constant at ${e.span}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Writing an interpolated expression like `"value \(1+1)"`-style `\(...)` inside a string constant that the grammar requires to be constant, e.g. a module name, property name, or other identifier-position string.

Common situations: Dynamically constructing a property/module name or AMQP-like constant string with a template expression; copy-pasting a normal string literal into an identifier position; refactoring code that moved a computed name into a constant position.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/57db7d0e88df7619. Report an issue: GitHub.

Appendix: source

Thrown at pkl-parser/src/main/java/org/pkl/parser/ParserImpl.java:1634

        }
        case STRING_ESCAPE_QUOTE -> {
          next();
          builder.append('"');
        }
        case STRING_ESCAPE_BACKSLASH -> {
          next();
          builder.append('\\');
        }
        case STRING_ESCAPE_RETURN -> {
          next();
          builder.append('\r');
        }
        case STRING_ESCAPE_UNICODE -> builder.append(parseUnicodeEscape(next()));
        case EOF -> {
          var delimiter = new StringBuilder(startTk.text(lexer)).reverse().toString();
          throw parserError("missingDelimiter", delimiter);
        }
        case INTERPOLATION_START -> throw parserError("interpolationInConstant");
        // the lexer makes sure we only get the above tokens inside a string
        default -> throw new RuntimeException("Unreacheable code");
      }
    }
    var end = next().span;
    return new StringConstant(builder.toString(), start.endWith(end));
  }

  private String getEscapeText(FullToken tk) {
    return switch (tk.token) {
      case STRING_ESCAPE_NEWLINE -> "\n";
      case STRING_ESCAPE_QUOTE -> "\"";
      case STRING_ESCAPE_BACKSLASH -> "\\";
      case STRING_ESCAPE_TAB -> "\t";
      case STRING_ESCAPE_RETURN -> "\r";
      case STRING_ESCAPE_CONTINUATION -> "";
      case STRING_ESCAPE_UNICODE -> parseUnicodeEscape(tk);
      default -> throw new RuntimeException("Unreacheable code");

View on GitHub (pinned to f3efcbfc9b)