// voxen field notes

How to Update a Minecraft Plugin to 1.21 (Even From Just the .jar)

2026-07-07 · 8 min read · [ GUIDE ]

It's the most predictable failure in server administration: you update your server to Minecraft 1.21, restart, and a plugin you've relied on for two years refuses to load. The developer abandoned it in 2022, the SpigotMC thread is dead, and your players want their crates back. This guide covers why plugins break between versions, how to update one by hand, and what to do when all you have left is the .jar.

Why plugins break between Minecraft versions

A plugin is compiled against a specific version of the Bukkit/Spigot/Paper API. When Mojang changes the game, the API changes with it — and code written for the old API stops compiling, stops loading, or (worst case) loads and then throws errors mid-game. The usual suspects:

  • The api-version gate. Every plugin declares the API generation it targets in its plugin.yml. A server refuses to load plugins targeting a newer API than it has — that's the classic Unsupported API version console error.
  • Renamed and removed methods. API surface gets deprecated and eventually deleted. A plugin calling a method that no longer exists dies with NoSuchMethodError at runtime — often only when the specific feature is used.
  • The 1.13 Flattening. Minecraft 1.13 renamed essentially every material and block ID in the game. Any plugin from the 1.8–1.12 era that touches items or blocks needs its material handling rewritten.
  • Text components. Modern Paper moved from legacy ChatColor codes to the Adventure component API; old chat code increasingly triggers deprecation warnings and broken formatting.
  • NMS internals. Plugins that reach past the API into net.minecraft internals are version-locked by design — Mojang's internal names change every release. These are the hardest ports, sometimes impossible without a rewrite.

Three errors account for most broken-plugin console logs:

terminal — paper 1.21 — the three classics
[ERROR]: Could not load 'plugins/crates.jar'
  org.bukkit.plugin.InvalidPluginException: Unsupported API version 1.16

[ERROR]: Error occurred while enabling Crates v2.3
  java.lang.NoSuchMethodError: org.bukkit.entity.Player.sendTitle(...)

[ERROR]: Could not load 'plugins/oldkits.jar'
  java.lang.ClassNotFoundException: net.minecraft.server.v1_16_R3.NBTTagCompound

Path 1: update it manually (you have the source)

If you have the plugin's source code and some Java, the manual route is well-trodden:

  1. Bump the build target. In pom.xml (or build.gradle), point the API dependency at the new version — e.g. io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT — and set Java 21, which modern Minecraft requires.
  2. Compile and read the errors. Every removed or renamed method surfaces as a compile error. Fix them one by one against the current API docs.
  3. Update api-version in plugin.yml to match your target.
  4. Hunt the silent breaks. Deprecated-but-still-present API compiles fine and misbehaves at runtime. Material names, chat formatting and scheduler usage deserve a test pass on a scratch server.

For a small plugin this is an afternoon. For anything with GUIs, persistence or version-specific hacks, budget considerably more — and it assumes you can read Java in the first place.

Path 2: you only have the .jar

This is the common case with abandoned plugins: the source was never published. A .jar can be decompiled — turned back into readable Java — with tools like CFR or Vineflower. Two honest caveats before you go down this road:

  • Rights first. Decompile plugins you own, commissioned, or whose license allows modification (open-source plugins generally do; premium plugins generally don't). Updating an abandoned free plugin for your own server is the typical legitimate case.
  • Obfuscated jars don't cooperate. Many premium plugins are deliberately scrambled before release. Decompiling those produces unreadable soup — no tool meaningfully recovers them.

Decompiled code compiles back fine, but you inherit the same manual migration work as Path 1 — on code with machine-generated variable names and no comments.

Path 3: let an AI port it (the Voxen way)

Voxen automates the whole chain — decompilation, API migration, recompilation — as a single flow called the Plugin Porter. It's the part of Voxen we built after watching how many "how do I update this plugin" threads end unresolved:

  1. Import. Upload the .jar (Voxen decompiles it server-side) or a source .zip, confirm you have the rights, and pick the target platform and version — say Paper 1.21.
  2. Port. The AI rewrites the code for the target API — events, materials, text components, api-version, build dependencies — and hands you a report of every change it made.
  3. Rebuild. The result is a normal Voxen project: hit BUILD, get a fresh .jar compiled against the real 1.21 API, and install it like any other plugin. If the code needs more work, you keep iterating with the AI in the editor.
terminal — voxen porter — crates 1.16 → 1.21
[cfr ] decompiled 14 classes ................. ok
[ai  ] materials remapped (1.13 flattening) .. ok
[ai  ] ChatColor → Adventure components ...... ok
[ai  ] plugin.yml api-version → 1.21 ......... ok
[mvn ] BUILD SUCCESS (12.4s)
[out ] crates-2.4.0.jar · Paper 1.21

The same expectations apply as with any porting method, automated or not:

  • Obfuscated jars are detected and declined upfront, before spending anything.
  • NMS-heavy plugins get a warning and a partial port — internals code usually needs follow-up in the editor.
  • A port consumes one AI generation (the free plan includes five, so you can try it without paying).

Which path is yours?

Your situationBest path
Source available, you know JavaManual update — full control, an afternoon of work
Source available, no JavaAI port from the source .zip
Only the .jar, plugin abandonedAI port — decompile + migrate + rebuild in one flow
Obfuscated premium pluginContact the author — nothing else genuinely works
Heavy NMS/internals usageAI port for the scaffolding, expect manual finishing
Whatever the path: test the updated plugin on a scratch server before production, and back up your world first — a plugin that loads cleanly can still have version bugs in the features you use least. If you're deciding between updating a plugin and replacing it with something new, see how to make a plugin without coding.