apple/pkl · error · JavaCodeGeneratorException
Annotation `$fqn` is not a valid Java class. The name of…
Error message
Annotation `$fqn` is not a valid Java class. The name of the annotation should be the canonical Java name of the class, for example, `com.example.Foo`.
What it means
JavaCodeGenerator.toClassName validates that each configured annotation FQN is a canonical Java class name containing at least one dot separating package from class name. A name with no '.' (e.g. `Foo`) cannot be split into package + class, so generation aborts with this message.
Solutions
- Prefix the annotation with its full package, e.g. `com.example.Foo` or `java.lang.Override`.
- Check the codegen config section (`annotations { ... }`) for keys missing dots.
- If using a default-package class, move the class into a package — JavaPoet requires a package.
- Re-run generation after fixing the FQN.
Example fix
// before
annotations { ["Deprecated"] = null }
// after
annotations { ["java.lang.Deprecated"] = null } Defensive patterns
Strategy: validation
Validate before calling
fun isValidJavaFqn(fqn: String) = fqn.contains('.') && fqn.split('.').all { it.matches(Regex("[A-Za-z_$][A-Za-z0-9_$]*")) } Type guard
fun String?.asCanonicalJavaName(): String? = this?.takeIf { it.lastIndexOf('.') > 0 } Try / catch
try { generate() } catch (e: JavaCodeGeneratorException) { if ("not a valid Java class" in e.message!!) fixAnnotationFqn() else throw e } Prevention
- Always use fully-qualified names including java.lang prefix in annotation configs
- Lint codegen config keys for a dot separator
- Copy FQNs from imports, not class declarations
When it happens
Trigger: In the pkl-java codegen config, an `annotations` mapping key (or similar FQN setting) is a bare class name like `Foo` or `Override` without a package, so lastIndexOf(".") returns -1.
Common situations: Copy-pasting a simple class name from Java source, configuring java.lang annotations without their package (java.lang.Override), or typos dropping the package prefix.
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
- Cannot generate Java code for a Pkl standard library module
- Cannot generate Java enum class for Pkl type alias
- Cannot generate Java enum class for Pkl type alias
- Cannot generate Kotlin code for a Pkl standard library…
- Cannot generate Kotlin enum class for Pkl type alias
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/91b6c527d205c744.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-codegen-java/src/main/kotlin/org/pkl/codegen/java/JavaCodeGenerator.kt:130
private val DATA_SIZE = ClassName.get(DataSize::class.java)
private val DATASIZE_UNIT = ClassName.get(DataSizeUnit::class.java)
private val PAIR = ClassName.get(Pair::class.java)
private val COLLECTION = ClassName.get(Collection::class.java)
private val LIST = ClassName.get(List::class.java)
private val SET = ClassName.get(Set::class.java)
private val MAP = ClassName.get(Map::class.java)
private val PMODULE = ClassName.get(PModule::class.java)
private val PCLASS = ClassName.get(PClass::class.java)
private val PATTERN = ClassName.get(Pattern::class.java)
private val URI = ClassName.get(java.net.URI::class.java)
private val VERSION = ClassName.get(Version::class.java)
private const val PROPERTY_PREFIX: String = "org.pkl.config.java.mapper."
private fun toClassName(fqn: String): ClassName {
val index = fqn.lastIndexOf(".")
if (index == -1) {
throw JavaCodeGeneratorException(
"""
Annotation `$fqn` is not a valid Java class.
The name of the annotation should be the canonical Java name of the class, for example, `com.example.Foo`.
"""
.trimIndent()
)
}
val packageName = fqn.substring(0, index)
val classParts = fqn.substring(index + 1).split('$')
return if (classParts.size == 1) {
ClassName.get(packageName, classParts.first())
} else {
ClassName.get(packageName, classParts.first(), *classParts.drop(1).toTypedArray())
}
}
}
val output: Map<String, String>View on GitHub (pinned to f3efcbfc9b)