apple/pkl · error · VmException

moduleIsNotConstAnnotation

moduleIsNotConstAnnotation

Error message

moduleIsNotConstAnnotation

What it means

In Pkl, `module` can only be referenced as a value inside a const annotation or within class bodies where the module object itself is a compile-time constant. When a `module` expression is evaluated in a scope where it would not be constant (e.g. a plain property or method body), the AST builder rejects it. The message key distinguishes annotation scopes (moduleIsNotConstAnnotation) from class scopes (moduleIsNotConstClass).

Source

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

  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();
      }
      if (scope == null) {
        throw exceptionBuilder()
            .evalError("moduleIsNotConst", currentScope.getName().toString())
            .withSourceSection(createSourceSection(expr))
            .build();
      }
      var messageKey =
          scope instanceof AnnotationScope ? "moduleIsNotConstAnnotation" : "moduleIsNotConstClass";
      throw exceptionBuilder()
          .evalError(messageKey)
          .withSourceSection(createSourceSection(expr))
          .build();
    }
    return symbolTable.isInTypeAliasScope
        ? new GetTypeAliasModuleNode(createSourceSection(expr))
        : new GetModuleNode(createSourceSection(expr));
  }

  @Override
  public ConstantValueNode visitNullLiteralExpr(NullLiteralExpr expr) {
    return new ConstantValueNode(createSourceSection(expr), VmNull.withoutDefault());
  }

  @Override
  public ExpressionNode visitBoolLiteralExpr(BoolLiteralExpr expr) {
    if (expr.isB()) {
      return new TrueLiteralNode(createSourceSection(expr));

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Remove the `module` expression from the annotation; annotations must be const-evaluable literals or simple type references.
  2. Move the module-relative value out of the annotation into a normal property or the annotated member itself.
  3. Use a fully qualified type or literal string in the annotation instead of module introspection.

Example fix

// before
@Deprecated { since = module.name }
prop x
// after
@Deprecated { since = "my/pkg" }
prop x
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on module introspection in an annotation, ensure the value is a literal:
const ann = new Annotation {
  since: "my/pkg" // literal, not `module.name`
}

Prevention

When it happens

Trigger: Writing `module` inside an annotation when the enclosing scope's const level permits non-const evaluation, i.e. `visitModuleExpr` detects the current scope is an AnnotationScope but the const check already failed.

Common situations: Using `module.name` or `module.dir` inside a custom annotation definition, attempting to parameterize annotations with module-relative values.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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