Build, install and test
The development loop: build a jar, put it on a server, restart, read the console.
Writing code is half the job; the other half is building it, getting it onto a server, and reading what the server says about it. On this page you will build jars from IntelliJ and from a terminal, install a plugin on a real server the right way, get more out of the test server, read the console and its stack traces, and check a plugin properly before you give it to anyone.
You should have a working project from Your first plugin. If you want to know what each file in it does, read Anatomy of a plugin project first.
Two ways to run your plugin
Every change you make ends up as a new jar. That jar can go two places: the test server on your own PC, which you use dozens of times a day, or a real server where players are, which you update when a version is ready.
Building the jar
Building means running the Gradle task called build. A task is one job Gradle knows how to do, such as compiling, packing the jar or starting the test server. There are three ways to run it, and they all do the same thing.
Pick Build Plugin Jar in the run drop-down at the top of IntelliJ and press the green Run button. The output appears in the Run window at the bottom.
Open the Gradle tool window (the elephant icon on the right edge of IntelliJ), open and double-click build. The same window lists every other task too, such as clean under build and runServer under run paper.
Open IntelliJ's terminal with . It starts in your project folder, so you can type the command straight away:
.\gradlew.bat buildThe .\ at the start means "the file in this folder". In a plain PowerShell window, first go to the project folder with cd, for example cd C:\Users\YourName\IdeaProjects\first-plugin.
A successful build looks like this. Each > Task line is one step: compile the Java code, copy the resources, pack the jar. Steps that have nothing to do (there are no tests yet) say NO-SOURCE or UP-TO-DATE.
.\gradlew.bat build> Task :compileJava> Task :processResources> Task :classes> Task :jar> Task :assemble> Task :compileTestJava NO-SOURCE> Task :processTestResources NO-SOURCE> Task :testClasses UP-TO-DATE> Task :test NO-SOURCE> Task :check UP-TO-DATE> Task :buildBUILD SUCCESSFUL in 9s3 actionable tasks: 3 executedThe jar is in build\libs, named after the project and its version: first-plugin-1.0.0.jar. The name comes from rootProject.name in settings.gradle.kts and version in gradle.properties. You may also see a note that "Deprecated Gradle features were used". It is a warning about the build file's style, not a problem with your plugin; Anatomy of a plugin project explains them.
When the build fails
If your code has a mistake, the build stops at compileJava and prints BUILD FAILED. Here the semicolon at the end of a line is missing:
.\gradlew.bat build> Task :compileJava FAILEDC:\Users\YourName\IdeaProjects\first-plugin\src\main\java\com\example\firstplugin\FirstPlugin.java:10: error: ';' expected getLogger().info("Hello! FirstPlugin is up and running.") ^1 errorFAILURE: Build failed with an exception.* What went wrong:Execution failed for task ':compileJava' (registered by plugin class 'org.gradle.api.plugins.JavaBasePlugin').> Compilation failed; see the compiler output below.BUILD FAILED in 1sRead the first error: line. It names the file, the line number after the colon (:10), and what Java expected. The ^ on the line below points at the exact spot. Fix that one error and build again; one mistake often causes several error lines, and they disappear together. No new jar is made when the build fails, so the old jar in build\libs is still the old code.
Installing on a real server
A real server is any Paper 26.3 server that is not your test server: one on another PC, a rented host, or a friend's server. Installing a plugin is always the same few steps.
Stop the server
Type
stopin the server console, or use the stop button of your hosting panel. Wait until it has fully shut down.Copy the jar into the plugins folder
Every Paper server has a
pluginsfolder next to itsserver.properties. Copy your jar frombuild\libsinto it.pluginsmy-serverplugins 1New Sort ViewNameSizebStatsfirst-plugin-1.0.0.jar23 KBA server's plugins folder with your jar in it Remove the old version
If an older jar of the same plugin is in the folder, delete it. With two jars of the same plugin, Paper refuses to choose properly and prints an error (see below).
Start the server and read the console
Look for
Enabling FirstPlugin v1.0.0and noERRORlines that mention your plugin. Then check in the game.
Two in-game commands confirm the install. /plugins lists every plugin, green when enabled and red when something went wrong. /version FirstPlugin shows which version is running, which matters when you are not sure the new jar was picked up.
Bukkit Plugins:
- FirstPlugin
FirstPlugin version 1.0.0
My first Paper plugin. It greets players when they join.
Both commands also work in the server console, without the slash. That is the easiest place to run them on a hosted server.
If two jars of the same plugin sit in the folder, you see this at startup, and you cannot be sure which version is running:
[14:10:02 ERROR]: [ModernPluginLoadingStrategy] Ambiguous plugin name 'FirstPlugin' for files 'plugins\first-plugin-1.0.0.jar' and 'plugins\first-plugin-0.9.0.jar' in 'plugins'On a hosting panel
Most rented servers use a web panel, often Pterodactyl or one based on it. The names of the buttons vary, but the steps are the same: stop the server in the console page, open the Files page, go into the plugins folder, use Upload to send your jar (and delete the old one), then start the server and watch the console page.
Why never reload
Old tutorials say to type /reload after copying a new jar. Do not. Restart the server instead, every time.
Reloading tries to switch plugins off and back on inside a running server. Your plugin's old objects, scheduled tasks and saved values can stay behind in memory, other plugins may keep pointing at your old classes, and players who are online keep whatever the old code gave them. The result is bugs that only happen after a reload, memory that keeps growing, and hours spent hunting problems that are not in your code. Paper itself warns against it.
In Paper 26.3, the plugin reload command is /bukkit:reload, and it asks for confirmation:
bukkit:reload[14:12:40 INFO]: CONSOLE: Are you sure you wish to reload your server? This command will be removed soon. Doing so may cause bugs and memory leaks. It is recommended to restart instead of using /bukkit:reload. To confirm, please type /bukkit:reload confirmPlain /reload on a 26.3 server is Minecraft's own command, which reloads data packs only. It does not touch plugins at all, so it will not load your new jar either. Plugins that register commands with Paper's newer command system even block plugin reloads completely. The short version: stop, replace the jar, start.
The test server in depth
The Run Paper Server button runs the Gradle task runServer from the run-paper plugin. Knowing what it does makes the test server much more useful.
What it does when you press Run
- It builds your jar, exactly like
builddoes (without the test steps). - It downloads the newest Paper build for the version in
gradle.properties, or reuses the copy it downloaded before:Run: Run Paper Server> Task :runServerLocated Paper 26.3 build 143 in local cache.Starting Paper... - It starts Paper in the
runfolder and tells it to load your jar straight frombuild\libs. That is why your jar never appears inrun\plugins.
The run folder
After the first start, run looks like a normal server folder, and you can change it like one:
- run/
- plugins/Data folders of your plugins (config.yml lives here). Drop other plugin jars here to test with them
- logs/latest.log for this run, older runs as .log.gz files
- world/The test world, plus world_nether and world_the_end
- server.propertiesPort, game mode, online mode, view distance and more
- eula.txtOnly matters for servers started without the EULA flag
- ops.jsonPlayers you made operator with op YourName
- Test with other plugins: put their jars in
run\plugins. They load next to yours, which is how you test a plugin that works together with, say, LuckPerms. - Change server settings: stop the server, edit
run\server.properties(for examplegamemode=creative), and start again. - Start over: stop the server and delete the
runfolder. The next run creates a fresh server and a new world.
The EULA flag
A Minecraft server only starts after its owner accepts Mojang's EULA, the end user license agreement for running a server. A real server writes eula.txt and stops until you change eula=false to eula=true. The test server skips that step because build.gradle.kts starts it with -Dcom.mojang.eula.agree=true, and Paper says so in yellow:
[14:02:07 WARN]: You have used the Paper command line EULA agreement flag.[14:02:07 WARN]: By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA).[14:02:07 WARN]: If you do not agree to the above EULA please stop your server and remove this flag immediately.Changing the Minecraft version
The test server's version is minecraftVersion in gradle.properties. The Paper API your code compiles against is paperVersion. Keep them about the same Minecraft version: when a new version comes out, change both, press the reload button that IntelliJ shows for Gradle files, and run again. If you have the paper-templates folder, update-paper-version.ps1 finds the newest Paper API build and writes it in for you.
The Debug button
Next to the green Run button is a green bug. It starts the same test server, but with IntelliJ's debugger attached. Click in the gray strip to the left of a line of code to set a red breakpoint; when the server reaches that line, everything pauses and IntelliJ shows you the values of all variables at that moment. Debugging like a pro teaches it step by step.
Reading the server console
The console is the server talking to you. Every line has the same four parts:
Your plugin writes these lines through its logger. This small plugin checks a few server settings when it starts and uses all three levels, so you can see what each one looks like:
Where this file livesbuild-and-run-consolesrcmainjavacomexamplebuildandrunconsoleStartupCheckPlugin.java
The package com.example.buildandrunconsole is the folder path com/example/buildandrunconsole inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- build-and-run-console/
- src/main/
- java/com/example/buildandrunconsole/Package com.example.buildandrunconsole
- StartupCheckPlugin.javayou are hereMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/buildandrunconsole/Package com.example.buildandrunconsole
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.buildandrunconsole;2 3import org.bukkit.plugin.java.JavaPlugin;4 5public final class StartupCheckPlugin extends JavaPlugin {6 7 @Override8 public void onEnable() {9 String version = getPluginMeta().getVersion();10 String minecraft = getServer().getMinecraftVersion();11 getLogger().info("StartupCheck " + version + " is running on Minecraft " + minecraft + ".");12 13 if (!getServer().getOnlineMode()) {14 getLogger().warning("online-mode is off. Anyone can join with any name.");15 }16 17 if (getServer().getMaxPlayers() < 2) {18 getLogger().severe("max-players is below 2, so nobody can play together.");19 }20 }21 22 @Override23 public void onDisable() {24 getLogger().info("StartupCheck stopped.");25 }26}- The version from
plugin.yml. Logging it at startup tells you at a glance which version of your jar the server is running. - Asks the server which Minecraft version it runs, as text such as
26.3. - An INFO line: normal news.
- The
!means "not": this runs when online mode is off. - A WARN line: something looks wrong, but the plugin keeps going.
- An ERROR line. Java calls this level "severe", the console prints it as
ERROR.
On a test server with online-mode=false and max-players=1 in server.properties, the console shows:
[14:20:09 INFO]: [StartupCheck] Enabling StartupCheck v1.0.0[14:20:09 INFO]: [StartupCheck] StartupCheck 1.0.0 is running on Minecraft 26.3.[14:20:09 WARN]: [StartupCheck] online-mode is off. Anyone can join with any name.[14:20:09 ERROR]: [StartupCheck] max-players is below 2, so nobody can play together.When you scan a long console, look for your plugin's name in brackets, and for WARN and ERROR. IntelliJ and most panels color them yellow and red. Use INFO for things that are good to know, WARN for things an admin should look at, and ERROR only when something really failed; a plugin that fills the console with red trains people to ignore it.
Stack traces
When your code crashes, Java prints a stack trace: the error, followed by the list of methods that were running when it happened. Here a plugin's onEnable read a setting that does not exist and then used the empty result:
1String greeting = getConfig().getString("greeting");2getLogger().info(greeting.toUpperCase());[14:22:30 INFO]: [FirstPlugin] Enabling FirstPlugin v1.0.0[14:22:30 ERROR]: Error occurred while enabling FirstPlugin v1.0.0 (Is it up to date?)java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "greeting" is null at first-plugin-1.0.0.jar//com.example.firstplugin.FirstPlugin.onEnable(FirstPlugin.java:11) ~[?:?] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:280) ~[paper-api-26.3.build.143-beta.jar:?] at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:201) ~[paper-26.3.jar:26.3-143-ff3655a] ... at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:593) ~[paper-26.3.jar:26.3-143-ff3655a] at net.minecraft.server.MinecraftServer.initPostWorld(MinecraftServer.java:641) ~[paper-26.3.jar:26.3-143-ff3655a] ... at java.base/java.lang.Thread.run(Thread.java:1474) ~[?:?][14:22:30 INFO]: [FirstPlugin] Disabling FirstPlugin v1.0.0It looks like a wall of text, but you only need three things from it:
- The headline:
Error occurred while enabling FirstPlugin. The crash happened inside youronEnable, so Paper switched the plugin off again right after (theDisablingline). The "(Is it up to date?)" part is a fixed phrase Paper always adds; it does not mean your plugin is outdated. - The exception line:
NullPointerException: Cannot invoke "String.toUpperCase()" because "greeting" is null. Java says exactly what went wrong:greetingwas empty (null), because the config has nogreetingsetting. - The first
atline in your package:com.example.firstplugin.FirstPlugin.onEnable(FirstPlugin.java:11). That is the file and line number to open. Everything below it is Paper and Java calling your code, which you can ignore.
Some stack traces have a Caused by: section further down; then the last Caused by is usually the real reason. Null, exceptions and stack traces explains exceptions properly, and the Error Doctor reads a pasted stack trace for you.
Log files
Everything in the console is also saved in the server's logs folder. logs\latest.log is the current run. When the server starts again, the previous log is packed into a file named after the date, such as 2026-10-03-1.log.gz (a .gz file is compressed; 7-Zip or most zip tools open it). When a player says "it broke last night", these files are where you look, and they are what you share when you ask someone for help.
Hot reload: what it can and cannot do
Restarting for every change takes a few seconds, and that is the normal way to work. While the server runs with the Debug button, IntelliJ can sometimes swap changed code into the running server without a restart. This is called HotSwap: after you edit a method and build (Ctrl+F9), IntelliJ offers to reload the changed classes, or you choose .
The Java runtime that runs Paper only allows small swaps:
| Change | HotSwap works? |
|---|---|
| Changing code inside an existing method, such as the text of a message | Yes. The next time the method runs, it uses the new code. |
| Adding or removing a method, a field or a class | No. Restart. |
| Changing a method's name or parameters | No. Restart. |
Changing plugin.yml or config.yml defaults | No. Restart. |
Changing onEnable | The swap works, but onEnable already ran and does not run again. Restart. |
So HotSwap is handy for tuning a message or a number inside an event handler. For everything else, stop and run again; nobody restarts the test server less often than they need to.
Versioning your plugin
A version number tells you and your server owners which build is which. Plugins usually use three numbers, MAJOR.MINOR.PATCH: raise the last one for a bug fix (1.0.1), the middle one for new features (1.1.0), and the first one for changes that break old setups, such as a new config layout (2.0.0). Releasing and sharing your plugin goes deeper.
In the guide's starter projects the version is written in two places, and you change both:
version=1.0.0ingradle.propertiesnames the jar.version: '1.0.0'inplugin.ymlis what the server shows in the console and in/version.
To keep it in one place, let Gradle write the version into plugin.yml while it builds. Add this block inside tasks { } in build.gradle.kts (it is the same block the paper-templates projects use):
1processResources {2 val properties = mapOf("version" to project.version, "apiVersion" to minecraftVersion)3 inputs.properties(properties)4 filteringCharset = Charsets.UTF_8.name()5 filesMatching(listOf("plugin.yml", "paper-plugin.yml")) {6 expand(properties)7 }8}- Changes the task that copies
src/main/resourcesinto the jar. - The values to fill in: the project version from
gradle.properties, and the Minecraft version forapi-version. - Tells Gradle to redo the copy when one of these values changes. Without it, a new version number could be skipped.
- Only these files get their placeholders filled.
Then use placeholders in plugin.yml:
1name: FirstPlugin2version: '${version}'3main: com.example.firstplugin.FirstPlugin4api-version: '${apiVersion}'Now changing version in gradle.properties updates both the jar name and the version the server shows.
Keep your old jars. Before you install a new version on a real server, copy the jar you are replacing into a folder such as releases on your PC (outside the project's build folder, which clean wipes). If the new version has a bug, going back is one file copy away.
Checklist before you share a plugin
Run through this list before a plugin goes to a real server or to another person. It catches the problems that are embarrassing to hear about from players.
- Raise the version and make sure
plugin.ymlshows the same number. - Build cleanly:
.\gradlew.bat clean buildends withBUILD SUCCESSFUL. - Start on a fresh server: stop the test server, delete
run, and run again. This is how a new server owner sees your plugin: no old config files, no old data. - Read the whole startup console: your Enabling line, no
WARNorERRORfrom your plugin, and a correct/version. - Test every feature in the game, as an operator and as a normal player (use
deop YourNamein the console). Permissions bugs only show up for non-operators. - Test the restart: stop and start the server once more and check that saved data and changed config values survive.
- Check
logs\latest.logfor errors that scrolled past while you were playing. - Keep the jar in your releases folder, with a line or two about what changed.
Break plugin.yml on purpose
Learning to read an error is easier when you know the cause. In your first-plugin project, change the main: line in plugin.yml so the class name has a small capital-letter typo: com.example.firstplugin.Firstplugin. Press Run Paper Server. Does the build succeed? What does the console say, and what color is your plugin in plugins? Then fix it.
Hint 1
The build only compiles Java and copies plugin.yml; it never checks what main: says. The problem shows up when the server tries to load the plugin, early in the startup.
Hint 2
Search the console for ERROR, or for the word main.
Show the solution
The build succeeds. The server starts too, but your plugin does not load:
[14:30:01 ERROR]: [ModernPluginLoadingStrategy] Could not load plugin 'first-plugin-1.0.0.jar' in folder 'C:\Users\YourName\IdeaProjects\first-plugin\build\libs'org.bukkit.plugin.InvalidPluginException: Cannot find main class `com.example.firstplugin.Firstplugin' at org.bukkit.plugin.java.PluginClassLoader.<init>(PluginClassLoader.java:84) ~[paper-api-26.3.build.143-beta.jar:?] at io.papermc.paper.plugin.provider.type.spigot.SpigotPluginProvider.createInstance(SpigotPluginProvider.java:125) ~[paper-26.3.jar:26.3-143-ff3655a] ...Caused by: java.lang.ClassNotFoundException: com.example.firstplugin.Firstplugin at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:208) ~[paper-api-26.3.build.143-beta.jar:?] ...Read it with the three-step method: the headline says Paper could not load the jar; the exception says it cannot find the main class com.example.firstplugin.Firstplugin; and Caused by: ClassNotFoundException confirms that no class with that exact name exists. None of the at lines are in your code, because your code never ran. There is no Enabling FirstPlugin line, no "Hello!", and plugins shows FirstPlugin in red.
The fix is to make main: match the class exactly, capital P included: main: com.example.firstplugin.FirstPlugin. Run again and the plugin is green.
One more startup check
Add a check to StartupCheckPlugin: read the server's view distance and log a warning if it is above 12 (high view distances cause lag), or an info line saying it looks good. Raise the plugin's version to 1.1.0, run the test server and find your new line in the console.
Hint 1
Type getServer().getView and let autocomplete show you the method that returns the view distance as an int.
Hint 2
Store it in a variable, then use if (viewDistance > 12) { ... } else { ... } with warning in one branch and info in the other.
Show the solution
getServer().getViewDistance() returns the view-distance from server.properties. The new lines go at the end of onEnable:
Where this file livesbuild-and-run-exercisesrcmainjavacomexamplebuildandrunexerciseStartupCheckPlugin.java
The package com.example.buildandrunexercise is the folder path com/example/buildandrunexercise inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- build-and-run-exercise/
- src/main/
- java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
- StartupCheckPlugin.javayou are hereMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
7@Override8public void onEnable() {9 String version = getPluginMeta().getVersion();10 String minecraft = getServer().getMinecraftVersion();11 getLogger().info("StartupCheck " + version + " is running on Minecraft " + minecraft + ".");12 13 if (!getServer().getOnlineMode()) {14 getLogger().warning("online-mode is off. Anyone can join with any name.");15 }16 17 if (getServer().getMaxPlayers() < 2) {18 getLogger().severe("max-players is below 2, so nobody can play together.");19 }20 21 int viewDistance = getServer().getViewDistance();22 if (viewDistance > 12) {23 getLogger().warning("view-distance is " + viewDistance + ". Values above 12 can cause lag.");24 } else {25 getLogger().info("view-distance is " + viewDistance + ". Looks good.");26 }27}- Read once and kept in a variable, because it is used twice: in the check and in the message.
- The check. Exactly one of the two branches runs.
And the version in plugin.yml:
Where this file livesbuild-and-run-exercisesrcmainresourcesplugin.yml
Files in src/main/resources are copied into the jar exactly as they are. Paper looks for plugin.yml at the top of the jar.
- build-and-run-exercise/
- src/main/
- java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
- StartupCheckPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlyou are hereTells Paper the plugin's name, version and main class
- java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1name: StartupCheck2version: '1.1.0'3main: com.example.buildandrunexercise.StartupCheckPlugin4api-version: '26.3'5description: Checks a few server settings at startup, including the view distance.- Raised to 1.1.0, because this is a new feature. Remember
gradle.propertiestoo, unless you use theprocessResourcesblock.
A new Paper server has a view distance of 10, so the console shows:
[14:35:12 INFO]: [StartupCheck] StartupCheck 1.1.0 is running on Minecraft 26.3.[14:35:12 INFO]: [StartupCheck] view-distance is 10. Looks good.Recap
- Build with Build Plugin Jar, the Gradle window, or
.\gradlew.bat build. The jar isbuild\libs\<project>-<version>.jar. - When a build fails, read the first
error:line: file, line number, and what Java expected. - To install: stop the server, copy the jar into
plugins, delete the old jar, start, and check the console,/pluginsand/version. - Never reload plugins. Restart the server.
- The test server lives in
run, loads your jar frombuild\libs, and accepts the EULA with a flag; deleterunfor a fresh server. - Console lines show time, level (INFO, WARN, ERROR), plugin and message. In a stack trace, find the exception line and the first
atline in your own package. - HotSwap only changes code inside existing methods; restarting is normal.
- Raise the version for every release, keep old jars, and test on a fresh server before sharing.
Quick quiz
You copied version 1.1.0 of your plugin into a real server's
pluginsfolder while it was running. What should you do next?Only a restart loads the new jar safely. Plain/reloadin 26.3 only reloads data packs, and/bukkit:reloadcauses leaks and strange bugs. The old jar must go, or Paper reports an ambiguous plugin name.In a stack trace, which line usually tells you where to look in your own code?
The lines are listed from where the error happened outward. The first one in your package names your file and line number; the lines below it are Paper and Java calling your code.Your plugin.yml's
main:line has a typo. When do you find out?Gradle copiesplugin.ymlwithout checking it. Paper readsmain:while loading plugins at startup and reportsCannot find main class.Which log level should a plugin use for "the config file has an unknown sound name, using the default instead"?
Something is wrong and an admin should fix it, but the plugin can carry on. That is exactly what WARN is for. ERROR is for things that really failed.While debugging, you added a brand-new method to your listener. Can HotSwap load it into the running server?
The Java runtime only allows method bodies to be swapped. New methods, fields or classes, and changes to plugin.yml, all need a restart.Where is the test server's log for the current run?
The test server is a normal server in therunfolder, and servers keep their logs inlogs. Older runs are packed into dated.log.gzfiles next to it.
Next steps
- How code reads: start the Java basics, now that you can build and test anything you write.
- Debugging like a pro: breakpoints, stepping and a calm way to find bugs.
- The main class and plugin lifecycle: what really happens between Loading, Enabling and Disabling.
- Error encyclopedia: common startup and runtime errors and their fixes.