apple/pkl · error · VmException

outerIsNotConst

outerIsNotConst

Error message

outerIsNotConst

What it means

AstBuilder.visitOuterExpr throws 'outerIsNotConst' when unqualified `outer` appears in a const context (annotation arguments and similar), since `outer` resolves dynamically through the enclosing object chain and cannot be evaluated as a constant. The input at fault is a bare `outer` expression in a const position.

Solutions

  1. Qualify the outer access (e.g. `outer.foo`) so the reference is static.
  2. Avoid `outer` inside annotation arguments; pass the needed value explicitly.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at pkl-core/src/main/java/org/pkl/core/ast/builder/AstBuilder.java:625 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/ast/builder/AstBuilder.java:625

            .withSourceSection(createSourceSection(expr))
            .evalError("thisIsNotConst")
            .build();
      }
    }
    return VmUtils.createThisNode(
        createSourceSection(expr), symbolTable.getCurrentScope().isCustomThisScope());
  }

  // TODO: `outer.` should probably have semantics similar to `super.`,
  // rather than just performing a lookup in the immediately enclosing object
  // also, consider interpreting `x = ... x ...` as `x = ... outer.x ...`
  @Override
  public OuterNode visitOuterExpr(OuterExpr expr) {
    if (!(expr.parent() instanceof QualifiedAccessExpr)) {
      var constLevel = symbolTable.getCurrentScope().getConstLevel();
      var outerScope = getParentLexicalScope();
      if (outerScope != null && constLevel.bigger(outerScope.getConstLevel())) {
        throw exceptionBuilder()
            .evalError("outerIsNotConst")
            .withSourceSection(createSourceSection(expr))
            .build();
      }
    }
    return new OuterNode(createSourceSection(expr));
  }

  @Override
  public ExpressionNode visitModuleExpr(ModuleExpr expr) {
    var currentScope = symbolTable.getCurrentScope();
    // cannot use unqualified `module` in a const context
    if (currentScope.getConstLevel().isConst() && !(expr.parent() instanceof QualifiedAccessExpr)) {
      var scope = currentScope;
      while (scope != null
          && !(scope instanceof AnnotationScope)
          && !(scope instanceof ClassScope)) {
        scope = scope.getParent();

View on GitHub (pinned to f3efcbfc9b)