Skip to main content

Resource Pack Manager Troubleshooting

This page only covers behavior that is currently confirmed in the ResourcePackManager codebase.

The single most useful first step for any RSPM issue is:

/rspm status

It prints version, deploy mode (standalone vs network-backend), a short non-secret network key fingerprint plus where that key came from, Java + Bedrock pack state, the active delivery path with URL, the resolved external host + auto-detected public IP, all relevant config flags, a proxy-deployment reminder (the network proxy jar is the same ResourcePackManager.jar), and Floodgate / Geyser-Spigot detection. The same command exists when the jar runs on a proxy and prints proxy-side equivalents (backend list, per-backend fetch outcomes, merged-pack state).

The console is quiet on purpose​

RSPM prints one line each time it freshly initializes a delivery path — the outcome:

[ResourcePackManager] Resource pack is live via self-hosting — http://play.example.com:25566/rspm.zip
[ResourcePackManager] Resource pack is live via automatic hosting — https://magmaguy.com/rsp/<uuid>

Everything else — each pack staged, each cluster merged, each stability check, each self-host probe and its result — is suppressed by default. A condition RSPM recovers from on its own is not reported as a warning. If a self-host probe fails and RSPM silently switches to remote hosting, that is a success, not a fault, and the console says nothing about it.

The outcome line means RSPM selected and published a delivery URL. It does not prove a particular client downloaded or rendered the pack. Verify with a joining player and inspect a known custom item or model. Before reporting a hosting or merging bug, turn the narration on:

/rspm verbose on

then /rspm reload. That command writes verboseLogging: true into plugins/ResourcePackManager/config.yml for you and the setting survives restarts, so /rspm verbose off when you're done. Editing the key by hand does the same thing. The Bedrock converter has a separate switch, bedrockConverterDebug, which is config-only.

Warnings you can legitimately see are genuine faults: repeated pack-delivery failure to a specific player, a client reporting INVALID_URL, an HTTP port that could not bind, both delivery paths failing, or a proxy that has polled several cycles without any backend producing content.

Players are not receiving the resource pack​

Check these first:

  • autoHost must be enabled if you want normal automatic delivery (selfHostForce is the explicit testing override)
  • the merged pack must exist and at least one delivery path (self-host or remote) must have succeeded
  • players receive the pack on join. Players who joined while no pack was published receive it when hosting becomes ready, including when hosting is re-registered later in the session (for example after an expired remote session)
  • Floodgate players are intentionally skipped by Java delivery because Geyser owns their Bedrock pack session

If needed:

  1. Run /rspm status and look at the "Hosting" section. Active delivery shows whether self-host, remote, or neither is currently in use.
  2. If "active delivery: not yet ready" — the mix or upload is still in progress. The plugin loud-banners this in the console when a player joins too early and will auto-send the pack the moment delivery is ready.
  3. If "active delivery: none — hosting disabled or failed" — autoHost is off, or self-host probes and remote upload both failed. See "Self-host sanity checks failed" and "Auto-hosting cannot reach the remote server" below.
  4. Set verboseLogging: true, run /rspm reload, watch console for the upload / self-host probe results, then rejoin with a test player. (Without that flag the probe steps are not printed — only the final "Resource pack is live via ..." outcome line is.)

The join offer is delayed by about one second. If a Java client reports FAILED_DOWNLOAD or DISCARDED, RSPM retries automatically up to three attempts for that player session. It does not retry a player decline, an INVALID_URL or a FAILED_RELOAD; repeated retry exhaustion and invalid URLs are logged as real faults.

FAILED_RELOAD means the client downloaded the pack but its own resource reload failed, so downloading the same pack again cannot help. RSPM logs Client <name> reported FAILED_RELOAD for the resource pack. Check that client's latest.log for the resource reload error; not retrying. Read that player's client latest.log to find the asset or pack metadata the client rejected.

If another pipeline owns hosting and delivery (autoHost: false), RSPM does not push its URL. For an HTTPS reverse proxy in front of RSPM, keep autoHost: true and use selfHostExternalUrl instead. This preserves automatic player delivery and the remote-host fallback.

ItemsAdder is installed, but its content is missing from the final pack​

This usually means ItemsAdder is still configured in a way that prevents ResourcePackManager from reading or hosting its output.

Use:

/rspm itemsadder configure

That command currently:

  • enables resource-pack.hosting.no-host.enabled
  • disables protection_1, protection_2, and protection_3
  • sets resource-pack.zip.compress-json-files: false
  • runs /iareload, then /iazip
  • waits for RSPM to merge the regenerated ItemsAdder export and reports whether the merge succeeded

It does not reload ResourcePackManager. After the merge message, check /rspm status for hosting.

If the command tells you ItemsAdder is already hosting its own pack, disable ItemsAdder hosting manually first and run the command again.

The merged pack is invalid or fails to upload​

ResourcePackManager's auto-host integration explicitly handles these server-side error types:

  • missing required files
  • file too large
  • invalid file format
  • missing session
  • remote server unavailable

RSPM checks the file-size limit itself before uploading: a Java pack over 50,000 KiB (51,200,000 bytes) is not uploaded, and the console prints Automatic hosting skipped: resource pack is <size> bytes; the limit is 51200000 bytes. RSPM then tries verified self-hosting instead. See Self-hosting.

If you hit one of these:

  1. Run /rspm reload to rebuild the pack.
  2. Check whether one of the source packs is malformed, encrypted, or otherwise unreadable.
  3. Check whether the final merged pack still contains a valid pack.mcmeta and pack.png at the root.

If an enabled pack cannot be extracted or staged, the current mix aborts and the console names the failing pack. Repair that pack, remove a manually added ZIP, or set isEnabled: false in its automatic integration config before reloading.

Overlay metadata and archive layout​

The final merge preserves authored overlay format declarations, including formats, min_format, max_format, and extra metadata. When packs share an overlay directory, the higher-priority entry wins.

One rewrite is made. Minecraft 1.21.9 and newer reject the whole pack.mcmeta when any overlay in the list reaches pack format 64 or lower and another overlay declares no formats. Two packs that are each valid can break that rule once their overlay lists are combined. When a merged list contains an overlay whose lower bound is 64 or lower, RSPM adds a formats range to every entry that declares only min_format and max_format. The range covers the same clients as the entry's own bounds, capped at 64 when it starts at 64 or lower. The collision log records Added the formats range to N overlay entries. Entries that already declare formats, or whose bounds do not parse, stay as written. RSPM does not otherwise reconcile different client-era ranges or repair invalid declarations; correct incompatible metadata in the source pack.

RSPM checks that an overlay directory is a nonblank relative path that does not escape the assembled pack root. Absolute paths, paths that normalize outside the root, and invalid paths fail this check. Passing it does not establish that Minecraft accepts the overlay's name or format metadata.

A ZIP with Pack Name/assets/ and Pack Name/pack.mcmeta has an extra wrapper directory. RSPM warns about it; re-archive the contents so assets/ and pack.mcmeta are at the ZIP root. Content-deduplicated archives are read through their central directory so entries sharing compressed data, including texture animation metadata, are retained.

Blocks atlas textures​

The merged blocks atlas expands directory sources to exact PNG resources owned by the merged pack. It preserves source ordering and sprite IDs. Pack textures whose animation-frame dimensions are unsafe for the required mip levels get deterministic nearest-neighbor copies under resourcepackmanager_internal:mip_safe/; the original files remain unchanged for font and other loaders.

Do not author content under the reserved resourcepackmanager_internal namespace. A collision is rejected. This process is not Java-to-Bedrock conversion and does not promise that every custom client shader or atlas extension is supported.

One broken pack no longer blocks everything forever​

A pack that cannot be staged fails the same way on every retry, so left alone it would wedge delivery permanently — the merge never completes and the same error repeats indefinitely. After three consecutive failures of the same file, RSPM drops that pack from the merge so the remaining packs can ship, and says so once, loudly:

[ResourcePackManager] Resource pack X.zip failed to stage 3 times in a row and has been excluded
from the merge so the remaining packs can be delivered. The merged pack is now INCOMPLETE ...

Read that as intended: the published pack is missing that plugin's content. The usual cause is a corrupt or partially written zip.

The exclusion clears itself. The failure record is keyed on the file's size and modification time, so repairing or replacing the file automatically retires the quarantine and the pack rejoins the next merge — no command, no restart. /rspm reload also resets all quarantine records from scratch. Failure counts that never reached three are dropped after any successful mix, so unrelated transient hiccups spread over a long uptime cannot accumulate into an exclusion.

On a SESSION_NOT_FOUND error from the remote auto-host, RSPM clears its session UUID and re-initializes on the next keep-alive tick — no manual intervention required.

One plugin's assets are overriding another plugin's assets​

This is controlled by priorityOrder in:

plugins/ResourcePackManager/config.yml

Higher entries win over lower entries.

For non-mergeable files, ResourcePackManager replaces the lower-priority file. For mergeable JSON files, it merges content instead. The currently mergeable JSON categories are:

  • sounds.json
  • language files
  • vanilla item model JSON in minecraft/models/item (non-recursive merge: only the overrides array is combined across packs, the rest of the file follows highest-priority-wins)
  • atlas files
  • font files
  • 1.21.4+ item model definitions in items/ (format-aware merge that respects predicate-tree structure)

pack.mcmeta is also merged specially: the highest pack_format wins and declared pack-format ranges are combined. Overlay entries keep their authored ranges and extra metadata; duplicate directories use the higher-priority entry. The only addition is a formats range on entries that need one for the combined list to load on 1.21.9+ clients (see Overlay metadata). RSPM does not otherwise repair incompatible author metadata. Additional nonconflicting metadata is preserved. Base atlas sources are merged into overlay atlas files to prevent overlays from shadowing base entries.

If you need to inspect what happened during the last merge, check:

plugins/ResourcePackManager/collision_log.txt

GUI text or font-based elements look wrong​

Font files are one of the JSON categories ResourcePackManager merges, but that does not guarantee two different font systems will behave well together in Minecraft.

If a font-driven menu or HUD looks wrong:

  1. Change priorityOrder so the pack you want to win is higher.
  2. Run /rspm reload.
  3. Check collision_log.txt to confirm collisions happened where you expected.

Resource pack changes are not showing up immediately​

ResourcePackManager has a watchdog for supported pack sources.

It waits until a changed pack remains unchanged for 3 seconds, then once all watched packs are stable the remix happens immediately.

If you are actively regenerating another plugin's pack, give it a few seconds after file writes stop. If in doubt, run /rspm reload after the upstream plugin finishes.

/rspm status says remote hosting, but I expected self-host​

This can happen when preferSelfHost: true (the default) and a self-host check fails. Reachability checks are logged at detail level and stay hidden unless verboseLogging: true; some messages include "This is OK." If remote hosting succeeds, the outcome is Resource pack is live via automatic hosting — .... Invalid settings, listener failures and remote communication failures can still produce warnings.

Run /rspm verbose on (or set verboseLogging: true) and /rspm reload to see which of the three layers failed:

  1. Layer 1 (heuristic) — the resolved external host is RFC1918 / loopback / link-local. Either set selfHostExternalHost to your real public hostname, or ensure the plugin can reach api.ipify.org / checkip.amazonaws.com.
  2. Layer 2 (local and advertised URL downloads) — RSPM downloads up to the first 1 KiB from http://127.0.0.1:<port>/rspm.zip and the exact player URL, comparing both with the local pack. HTTP 200 or 206, matching reported lengths and the expected Content-Range for 206 are required. Redirects, wrong bytes, missing files and server-side NAT-loopback failures reject self-hosting.
  3. Layer 3 (external reachability probe) — magmaguy.com must report the announced URL reachable with HTTP 200 or 206. A closed HTTP port, failed request or unavailable probe service rejects automatic self-hosting. The status and any reason code are printed under verboseLogging.

Fixes (in order of preference): open the HTTP port at your firewall + router, set selfHostExternalHost to a routable hostname, or set preferSelfHost: false to try remote hosting first. Set selfHostEnabled: false as well if self-hosting must never be the fallback, and leave selfHostForce: false.

If the probe service is unreachable, self-hosting remains unverified and RSPM tries remote hosting. Remote-failure fallback must pass the same self-host checks. Only selfHostForce: true bypasses verification; if both automatic paths fail, RSPM cannot announce a new delivery URL. Successful probes still do not prove a complete download and pack acceptance from every player's network.

See Self-hosting for the full decision tree.

Auto-hosting cannot reach the remote server​

ResourcePackManager's built-in remote host talks to:

https://magmaguy.com/rsp/

If that connection fails, the plugin logs communication warnings and cannot use the remote fallback until it reconnects successfully.

Your options are:

  1. fix the server's outbound HTTPS connectivity
  2. wait for the remote service to become reachable again
  3. disable autoHost and host the generated zip yourself
  4. open your HTTP port, set selfHostExternalHost to your public hostname, and keep preferSelfHost: true. The explicit hostname skips public-IP auto-detection, but the local, advertised-URL and external checks must still pass. An unreachable probe service prevents automatic self-host selection.

I want to self-host the merged pack through my own web server​

The code-supported setup is:

  1. Set autoHost: false.
  2. Set resourcePackRerouting if you want ResourcePackManager to write an extra copy into an existing folder.
  3. Host ResourcePackManager_RSP.zip yourself.

resourcePackRerouting is resolved relative to the plugins directory, and the target folder must already exist.

If instead you want to use RSPM's built-in self-host HTTP server (different thing — same JVM as the plugin), see Self-hosting.

I need to inspect what remote data is stored for this server​

Use:

/rspm data_compliance_request

If there is an active remote hosting session, ResourcePackManager downloads the response into:

plugins/ResourcePackManager/data_compliance/data.zip

RSPM also writes ReadMe.md in the same data_compliance folder.

If there is no remote session (e.g. you're using self-host), the command reports that there is no remote data to request.

Bedrock pack is not being generated​

bedrockConversionEnabled defaults to true, so it should run automatically. Run /rspm status first — the Bedrock Pack section will tell you why the pack isn't on disk:

  • "No Bedrock target detected" — no local Geyser-Spigot, no local Floodgate, and not in network mode. Conversion is intentionally skipped. Install Floodgate (for proxy setups) or Geyser-Spigot (for standalone setups) and /rspm reload.
  • "Network mode is active so this backend SHOULD produce a Bedrock pack. The file is missing" — usually the first mix cycle hasn't completed yet (wait ~30s after boot), or conversion found neither convertible item mappings nor allowed entity bundles, or conversion threw. Search the console for [BedrockConverter] warnings. With bedrockConverterDebug: true, the scanner also logs Generic scanner: discovered N item definitions; a count of 0 means the merged pack has no convertible item definitions. (The status diagnostic quotes this line as discovered 0 items definition files.)

If Geyser auto-detection fails:

  1. Set bedrockGeyserFolder in config.yml to the path of your Geyser data folder (e.g. Geyser-Spigot).
  2. Absolute paths work. A relative path is tried from the server working directory first, then relative to the plugins directory.

The converter auto-detects Geyser in plugins/Geyser-Spigot/, any plugins/Geyser-*/ variant, or config/Geyser-*/ for Fabric/NeoForge setups.

For per-item / per-bone log output, set bedrockConverterDebug: true and reload.

Bedrock: live provider skipped because a legacy pack exists​

If the console reports Legacy RSPM Bedrock pack detected, Geyser already scanned an old ResourcePackManager_Bedrock.zip from its pack directory during boot. Deleting that file while the process is running would leave Geyser holding an in-memory codec for a path that no longer exists, so RSPM deliberately skips its live pack provider for that boot.

Fully stop the server, delete only the exact legacy file path printed by RSPM, then start the server again. Do not use /reload for this migration. The current pack remains in plugins/ResourcePackManager/output/ and is served per session; it does not belong in Geyser's packs/ directory.

Bedrock players see held items in the wrong position​

First verify that the intended model and latest pack loaded: reconnect the Bedrock client so it receives the current pack. RSPM derives the held pose from the Java model's display.firstperson_righthand and display.thirdperson_righthand transforms, so a pose that is also wrong on Java is fixed in the Java model. If Java looks right and Bedrock does not, report it with the model file.

bedrock_display_offsets.yml and its offset settings were removed and are no longer read; editing an old copy has no effect. See Held-item poses.

Custom armor textures are missing on Bedrock players​

Custom armor renders on Bedrock by combining the vanilla armor geometry with the Java texture as a visible layer. For this to work, the source plugin's pack must define an equipment file under assets/<namespace>/equipment/<material>.json alongside the items definition. If the conversion log shows the item but no armor texture appears in-game, verify that file exists in the merged pack.

Proxy: a backend says it has no network key​

On the backend, /rspm status shows Network key source: not set — the proxy sends one when a player next connects here, and the console repeats "This backend is behind a proxy but has no network key yet".

A missing plugins/floodgate/key.pem is not the cause — that file is optional now. The proxy owns the key: it loads its own network-key file, or seeds once from Floodgate's key.pem if present, or mints a fresh key, and then pushes it to each backend when a player connects there.

Check, in order:

  1. Has a player connected to that backend since the proxy started? The grant rides on a player connection.
  2. Is ResourcePackManager.jar actually on the proxy? The backend stages a copy of its own jar for you at plugins/ResourcePackManager/proxy-extension/ResourcePackManager.jar and prints that path — copy it to the proxy's plugins/ and restart the proxy.
  3. On Velocity with modern forwarding, does the backend's forwarding secret match the proxy's? A modern-forwarding backend deliberately rejects an unsigned or wrongly-signed grant; its log states which. Fix the secret on both sides and the next player connect retries by itself.
  4. Compare the Network key fingerprint lines from /rspm status on both sides. Identical fingerprints indicate the same network identity; inspect fetch outcomes to verify connectivity. The key itself is never printed.

See Proxy networks for the full sequence.

If /rspm status instead says NetworkSync isn't running and suggests a missing Floodgate key.pem, read the earlier boot error. That parenthetical hint is stale: the current proxy can generate and persist its own network key without Floodgate. The initialization error, filesystem permissions, and backend connectivity determine the next step. If the proxy /rspm command is missing entirely, check the boot log for a network identity failure.

Incomplete publication rollback​

If publishing a Bedrock pack, proxy inbox, or merged pack fails and the previous files cannot be fully restored, RSPM retains recovery copies and logs their directory and affected destinations. It also attempts to withdraw the incomplete artifact set from use. Preserve the logged recovery directory, resolve the filesystem errors, and inspect pack and mapping consistency before retrying. A failed rollback is not a successful publication.

Proxy: "Could not establish persistent RSPM network identity"​

Current releases do not run on an unsaved key. If the proxy cannot save a newly resolved key to network-key, or cannot read an existing network-key file, the proxy role stops during startup with Could not establish persistent RSPM network identity: ... or Cannot read established RSPM network identity. Network sync, Bedrock delivery and the proxy /rspm command do not start, so backends keep their existing keys rather than being linked to a key that could change at the next restart.

Fix the filesystem permissions on the proxy plugin's data folder (plugins/resourcepackmanager/ on Velocity, plugins/ResourcePackManager/ on BungeeCord), then restart the proxy. A malformed network-key file that can be read is replaced automatically.

Proxy: "no merged pack" after several poll cycles​

First check the confirmed RSPM participant count in /rspm status. A fresh proxy with no confirmed participants continues backend discovery without treating every registered server as a failed RSPM backend. Unconfirmed servers do not delay pack synchronization.

After four consecutive empty poll cycles with confirmed participants, RSPM logs a diagnostic banner listing the participants, the HTTP URLs it tried and their outcomes. The default poll interval is five seconds; network operations can extend elapsed time. The banner explains the most common fixes:

  • CONNECT_FAILED on every backend → the proxy can't reach the backend's HTTP port. Check that the address in velocity.toml / config.yml is one the proxy can actually reach (not e.g. a Docker-internal name that doesn't resolve from the proxy's network), and that the backend's announced HTTP port is open between proxy and backend. The banner prints the exact URL it tried; before a backend has announced its port the proxy falls back to mcPort + network-http-offset-v2, so an early CONNECT_FAILED can also mean that fallback port isn't reachable yet.
  • NOT_FOUND_404 on every backend → backends are up but not producing a Bedrock pack. Run /rspm status on each backend; the Bedrock Pack diagnostic block will tell you why.

The banner fires once per stuck period and an "NetworkSync: recovered" line is logged when at least one backend starts returning content again. See Proxy networks for more.

Proxy: Bedrock players see no models on first proxy boot​

Geyser registers its custom-item table at proxy startup only. If the proxy started before any backend produced a Bedrock pack, Geyser is running with an empty mappings table and stays that way for the rest of the session.

The fix is to restart the proxy once the proxy has logged Merged Bedrock pack published at .... RSPM pre-deploys the previous run's mappings on proxy boot so later boots can register saved mappings. New identifiers introduced after startup can require this restart again.

Backend: "Backend HTTP server failed to bind on port X"​

In network mode, the backend exposes its Bedrock outputs through a small HTTP server. If the port is in use or unavailable, you'll see a multi-line [ERROR] block in the console. Fixes:

  • Set selfHostPort to a different positive value in config.yml.
  • Or change networkHttpOffset-v2 to push the auto-derived port away from the collision (e.g. RCON on mcPort + 1? set it to 2 or 3). You do not need to update the proxy to match: once the backend binds successfully it announces its actual HTTP port to the proxy automatically, so the proxy's own network-http-offset-v2 only matters as a pre-announcement guess.

While the backend HTTP server is down, this backend's Bedrock pack won't reach the proxy via direct fetch. The magmaguy.com relay fallback still works (the backend pushes its files to the relay and the proxy fetches them through there).

Cleaning up an outdated v1 config​

Operators upgrading from RSPM v1 may have a dead networkHttpOffset (no -v2) key in their config.yml. RSPM v2 intentionally does not read the old key — you get the v2 default (1) written to config on next boot automatically. The dead v1 key sits in your config as a harmless artifact until you clean it up by hand.