apple/pkl · error · GradleException

Could not find a source set for code generator

Error message

Could not find a source set for code generator '${name}'. Either apply a JVM plugin (e.g. 'java') or set the sourceSet property explicitly.

What it means

When configuring code-generation tasks, each CodeGen spec must resolve to a Gradle SourceSet. If the spec's sourceSet property is unset and no JVM plugin (java/kotlin) has been applied to the project, there is no default source set to resolve, and the plugin throws GradleException. It exists to tell users they must either apply a JVM plugin or set sourceSet explicitly.

Solutions

  1. Apply a JVM plugin to the same project: add `java` (or `kotlin`) to its plugins block.
  2. Set the source set explicitly in the codegen block: `sourceSet = sourceSets.main` (or `sourceSets.test`).
  3. Check you applied the codegen config in the correct subproject, not the root.
  4. If the module is intentionally non-JVM, remove the codegen block and invoke codegen via the CLI instead.

Example fix

// before (build.gradle.kts)
pkl { codegen { generators { register("pklGen") { ... } } } }
// after
plugins { `java` }
pkl { codegen { generators { register("pklGen") { sourceSet = sourceSets.main; ... } } } }
Defensive patterns

Strategy: validation

Validate before calling

val codegen = project.extensions.getByType<PklExtension>().codegen
codegen.generators.forEach { require(it.sourceSet.isPresent || project.plugins.hasPlugin(JavaPlugin::class.java)) { "Apply 'java' or set sourceSet for generator ${it.name}" } }

Type guard

fun Project.hasDefaultSourceSet() = plugins.hasPlugin(JavaPlugin::class.java) || plugins.hasPlugin(KotlinPluginWrapper::class.java)

Try / catch

try { pkl.configure(...) } catch (GradleException e) { if (e.message?.contains('source set')) logger.error('Apply java/kotlin plugin or set sourceSet on generator ' + name); throw e }

Prevention

When it happens

Trigger: Applying pkl-codegen in a project (or subproject) without the `java` or `kotlin` plugin, leaving codegen { generator { ... } } blocks without a sourceSet = ... assignment; running configureJavaCodeGenTasks/configureKotlinCodeGenTasks over such a spec.

Common situations: Pkl codegen added to a non-JVM module like a pure Pkl or docs subproject; a multi-project build where the JVM plugin is applied at the root but not in the subproject containing the codegen block; migrating from an older plugin version with different defaults.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at pkl-gradle/src/main/java/org/pkl/gradle/PklPlugin.java:435

                                .getSourceDirectories()
                                .filter(
                                    f ->
                                        !f.getAbsolutePath()
                                            .startsWith(
                                                specOutputDir.getAsFile().getAbsolutePath()))
                                .getFiles()));
  }

  private void configureCodeGenSpecSourceDirectories(
      Project project,
      CodeGenSpec spec,
      String languageName,
      Function<? super SourceSet, ? extends Optional<SourceDirectorySet>>
          extractSourceDirectorySet) {
    var task = project.getTasks().named(spec.getName(), CodeGenTask.class);
    var sourceSet = spec.getSourceSet().getOrNull();
    if (sourceSet == null) {
      throw new GradleException(
          "Could not find a source set for code generator '"
              + spec.getName()
              + "'. Either apply a JVM plugin (e.g. 'java') or set the sourceSet property explicitly.");
    }
    extractSourceDirectorySet
        .apply(sourceSet)
        .ifPresentOrElse(
            dirSet -> dirSet.srcDir(task.flatMap(t -> t.getOutputDir().dir(languageName))),
            () ->
                project
                    .getLogger()
                    .debug(
                        "Source directory set for language {} is not available, "
                            + "will not add task {} as its dependency",
                        languageName,
                        task.getName()));
    sourceSet.getResources().srcDir(task.flatMap(t -> t.getOutputDir().dir("resources")));
  }

View on GitHub (pinned to f3efcbfc9b)