Troubleshooting Keystone

Start with the first error in the build or server log, not the last cascade. Include the exact Keystone version, your built jar, plugin.yml, server software/version, Java version and the output of keystone.platform().describe() when asking someone to reproduce a runtime problem.

Maven cannot resolve keystone-parent

Maven resolves a parent before it reads the child project's <repositories>. Put the bwmp Nexus repository in an active profile in ~/.m2/settings.xml, as shown in Getting started, or install the exact Keystone version locally. Confirm with mvn help:effective-settings.

The build rejects keystone.libs.package

Set a valid, plugin-unique package such as com.example.myplugin.libs. Do not use the default, another plugin's relocation target, a path with /, or a package ending in .keystone.

Inspect the packaged jar, not only the compile classpath. It should contain Keystone below your relocation prefix and should not contain unrelocated dev/bwmp/keystone/ classes.

NoClassDefFoundError: dev/bwmp/keystone/...

The usual causes are:

  1. The shade goal did not run, so Keystone was not included.
  2. Your public API exposes an unrelocated Keystone type.
  3. A reflection string or service descriptor names the pre-relocation class.

Run mvn package, inspect target/*.jar, and follow the publishing an API boundary rule. A dependency being present in the IDE does not prove it is present in the shipped jar.

Adventure types do not match

If a method expects Paper's Component but the value comes from your relocated Adventure copy, the two identical-looking class names are different runtime types. Either keep components internal and send through MessageService, or use the Paper-only Adventure build and ensure Adventure is neither shaded nor relocated.

Folia refuses to load the plugin

Add folia-supported: true to plugin.yml. If it loads but throws thread-access errors, search for direct Bukkit scheduler usage and route work through atEntity, atLocation, run or async according to the state touched. The declaration is only a load gate; it is not a safety layer.

A reload partially applies

Parse into a new immutable candidate, collect every issue in LoadReport, and call Snapshot.set(candidate) only when there are no errors. Mutating the live settings object while parsing defeats the snapshot model and is unsafe on Folia.

bStats logs a relocation warning

The packaged jar contains unrelocated org.bstats classes. This commonly happens after using combine.self="override" for the Paper-only Adventure build. Restore the bStats relocation or remove keystone-metrics if metrics are not used.

Telemetry does not start

Check both plugins/Keystone/telemetry.yml and plugins/bStats/config.yml. Either opt-out disables Keystone telemetry. A blank server-id, read-only plugin directory or failure to persist the file also keeps it disabled rather than generating a new identity every boot.

Before filing an issue

  • Reproduce with the exact released Keystone version, not a floating snapshot.
  • Confirm the failure remains on a supported server and Java version.
  • Include the first stack trace and the platform description.
  • Reduce the problem to one subsystem if possible.
  • Check the changelog for breaking build or API changes.

Include Keystone.version(), Keystone.isRelocated() and keystone.platform().describe() in the baseline. Reproduce with the final shaded consumer jar, because an IDE run or unshaded test jar can hide the exact relocation failure being investigated. Third-party support is not guaranteed, so a minimal reproduction is especially important when reporting external use.