skip to content

Your convention plugin calls `versionCatalogs.named("libs")` and it throws because the catalog isn't named `libs`, or a second catalog exists. How do you reliably target the right catalog from inside the plugin?

level: middleimportance: nice to knowfreq 25%

answer

  1. named() = exact-name lookup
  2. default name is 'libs'
  3. UnknownDomainObjectException if absent
  4. catalogNames to inspect/guard
  5. multiple catalogs each named separately

basics

~10 s

named(name) must match the catalog's declared name exactly. If you have multiple or a custom name, pass that name; to be defensive, check catalogNames/find(name) first, or iterate, instead of assuming "libs".

solid answer

~40 s

`VersionCatalogsExtension.named("libs")` resolves the catalog whose name is exactly `libs` — the default for `gradle/libs.versions.toml`. If a project declares the catalog under another name (e.g. `from(files(...))` as `"deps"`) or defines several catalogs, `named("libs")` will throw `UnknownDomainObjectException`. To be robust in a shared plugin, don't hardcode blindly: you can inspect `extension.catalogNames` (the set of registered names) and pick the right one, or guard with a clear failure message. Using the conventional default `libs` everywhere is the simplest contract, but a convention plugin shipped to many builds should fail with an actionable message ("expected a 'libs' catalog") rather than an opaque exception. Multiple catalogs (e.g. `libs` plus a `tools` catalog) each get their own accessor and their own `named(...)` entry.

code

kotlin · 6 lines
kotlin
val ext = project.extensions.getByType<VersionCatalogsExtension>()
require("libs" in ext.catalogNames) {
    "This convention plugin needs a 'libs' catalog; available: ${ext.catalogNames}"
}
val libs = ext.named("libs")
val tools = if ("tools" in ext.catalogNames) ext.named("tools") else null

go deeper

for a junior

Know that named("libs") targets the default catalog and the name must match.

for a middle

Handle a missing/renamed catalog by checking catalogNames and failing with a clear message; know multiple catalogs are independent.

for a senior

Treat the catalog name as part of a shared plugin's contract and validate it defensively for builds you don't control.

for a principal

Define an org convention (always libs, plus optional named catalogs) and document the plugin's catalog contract so consuming teams can satisfy it predictably.

## How catalogs are named The default catalog is `libs`, auto-created from `gradle/libs.versions.toml`. You can declare additional or custom-named catalogs in settings: ```kotlin // settings.gradle.kts dependencyResolutionManagement { versionCatalogs { create("libs") { from(files("gradle/libs.versions.toml")) } create("tools") { from(files("gradle/tools.versions.toml")) } } } ``` Each catalog gets its own type-safe accessor (`libs.*`, `tools.*`) in scripts, and each is a distinct entry in `VersionCatalogsExtension`. ## What named() does and how it fails ```kotlin val extension = project.extensions.getByType<VersionCatalogsExtension>() val libs = extension.named("libs") // throws UnknownDomainObjectException if no 'libs' ``` `named(name)` is an exact-name lookup. If the project's catalog is called `deps`, or only `tools` exists, `named("libs")` throws. In a convention plugin distributed across many builds you can't always assume the name. ## Defensive strategies ```kotlin val ext = project.extensions.getByType<VersionCatalogsExtension>() require("libs" in ext.catalogNames) { "Convention plugin requires a 'libs' version catalog; found: ${ext.catalogNames}" } val libs = ext.named("libs") ``` - `catalogNames` exposes the registered set, so you can check before calling `named`. - Provide an actionable error so consumers know to declare/rename the catalog. - For multiple catalogs, call `named("libs")` and `named("tools")` separately — they don't merge. ## Practical guidance For a single-team monorepo, standardizing on the default `libs` and calling `named("libs")` is perfectly fine. The defensive checks matter most when a convention plugin is published and applied in builds you don't fully control, where the catalog name is part of the plugin's implicit contract.

  • What exception does `named("libs")` throw when no such catalog exists?
    An `UnknownDomainObjectException` — the standard Gradle error for looking up a missing named domain object. Wrapping it with a `require`/clear message makes the failure actionable for consumers.
  • If a build has both `libs` and `tools` catalogs, how do you read both?
    Call `named("libs")` and `named("tools")` separately — each catalog is independent and isn't merged. Their accessors and `find*` lookups are scoped to that catalog.

saying these in an interview costs you the question

  • Assuming there is always exactly one catalog named `libs`.
  • Letting `named` throw an opaque UnknownDomainObjectException instead of a message that tells the consumer what to do.
  • Believing multiple catalogs merge into one namespace.

context