quarkusio/quarkus · error · MojoExecutionException

Unable to render config roots for top level prefix: ${topLev

Error message

Unable to render config roots for top level prefix: ${topLevelPrefix} in extension: ${extension}

What it means

The config-doc-maven-plugin's GenerateConfigDocMojo renders per-config-root Asciidoc reference pages using Qute. When generateConfigReference(...) or Files.writeString fails for a top-level prefix's config root, the exception is wrapped in this MojoExecutionException naming the prefix and extension. It indicates Qute template rendering or file output failed for that config root.

Source

Thrown at devtools/config-doc-maven-plugin/src/main/java/io/quarkus/maven/config/doc/GenerateConfigDocMojo.java:134

            Path configRootPath = null;

            for (Entry<ConfigRootKey, ConfigRoot> configRootEntry : extensionConfigRootsEntry.getValue().entrySet()) {
                String topLevelPrefix = configRootEntry.getKey().topLevelPrefix();
                ConfigRoot configRoot = configRootEntry.getValue();

                // here we generate a file even if there are no items as it's used for the Reactive Oracle SQL client

                configRootPath = resolvedTargetDirectory.resolve(String.format(CONFIG_ROOT_FILE_FORMAT,
                        extension.artifactId(), topLevelPrefix, normalizedFormat.getExtension()));
                String summaryTableId = formatter
                        .toAnchor(extension.artifactId() + "_" + topLevelPrefix);
                Context context = new Context(summaryTableId, false);

                try {
                    Files.writeString(configRootPath,
                            generateConfigReference(quteEngine, context, extension, configRoot, "", true));
                } catch (Exception e) {
                    throw new MojoExecutionException("Unable to render config roots for top level prefix: " + topLevelPrefix
                            + " in extension: " + extension, e);
                }
            }

            // if we have only one top level prefix, we copy the generated file to a file named after the extension
            // for simplicity's sake
            if (extensionConfigRootsEntry.getValue().size() == 1 && configRootPath != null) {
                Path extensionPath = resolvedTargetDirectory.resolve(String.format(EXTENSION_FILE_FORMAT,
                        extension.artifactId(), normalizedFormat.getExtension()));

                try {
                    Files.copy(configRootPath, extensionPath, StandardCopyOption.REPLACE_EXISTING);
                } catch (Exception e) {
                    throw new MojoExecutionException("Unable to copy extension file for: " + extension, e);
                }
            }
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Read the wrapped cause in the MojoExecutionException — it names the actual rendering (Qute) or IO failure; fix that first.
  2. Run with -e / -X (mvn -e) to see the full stack trace and identify the failing template or path.
  3. Verify the output directory (resolvedTargetDirectory) exists and is writable.
  4. Rebuild after fixing the extension's @ConfigMapping annotations if the config model itself is malformed.

Example fix

// before
<outputDirectory>/docs/readonly</outputDirectory>
// after
<outputDirectory>${project.build.directory}/generated-docs</outputDirectory>
// or fix the cause reported in the nested exception
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check output location
Path out = resolvedTargetDirectory;
if (!Files.isDirectory(out)) Files.createDirectories(out);
if (!Files.isWritable(out)) throw new IllegalStateException("Not writable: " + out);

Try / catch

try {
    String rendered = generateConfigReference(quteEngine, context, extension, configRoot, "", true);
    Files.writeString(configRootPath, rendered);
} catch (Exception e) {
    throw new MojoExecutionException("Unable to render config roots for prefix " + topLevelPrefix, e);
}

Prevention

When it happens

Trigger: Running the generate-config-doc goal when rendering a config root of a top level prefix throws — e.g. a Qute template error, invalid template data, or inability to write configRootPath (missing parent dir, permissions).

Common situations: Generating docs for an extension whose config mapping produces data the Qute templates can't handle (new/changed config root shape); read-only target directory; malformed extension metadata in the merged model.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/ffc2d6cf4386de8b. Report an issue: GitHub.