Dev Fixes

This is a collection of a bunch of random problems and fixes for Fabric developers.

Fabric API mixins aren't applying

Mixin apply for mod fabric-registry-sync-v0 failed...
InvalidMixinException @Shadow method method_63535 in fabric-registry-sync-v0.mixins.json:SimpleRegistryMixin 
from mod fabric-registry-sync-v0 was not located in the target class...

Fixes:

  1. Check that you're using the right version of Fabric API for your Minecraft version.
  2. Try regenerating run configs
  3. Try making your dependencies non-transitive. Using the Kotlin Gradle DSL:
modImplementation("me.lucko:fabric-permissions-api:${property("deps.permissions_api")}") {
    isTransitive = false
}

Run configurations are broken

To regenerate them:

  1. Delete .idea/runConfigurations
  2. Reload the Gradle project
  3. Reload .idea from disk (or restart IntelliJ)

registration of listener on 'Gradle.addListener' is unsupported

It's not your fault! See fabric-loom#1349. To fix it, add this to your gradle.properties:

org.gradle.configuration-cache=false

(yes, that's it)

IllegalClassLoadError: good.testmod.mixin.TestModClient is in a defined mixin package...

Non-mixin classes (like TestModClient presumably is) can't be in your mixin package.

AccessWidenerFormatException: Invalid access widener file header. Expected: 'accessWidener <version> <namespace>'

Fix your access widener. If you don't have one, update Fabric Loader to >=0.18.0 - you likely have a dependency that uses classtweakers, but doesn't correctly declare that it needs Loader 0.18.0+ (something in Fabric API does/did this for a while).

StackOverflowError from a vanilla method recursing infinitely, but it doesn't call itself

Most likely, there's a mixin involved, and you'll see that in the stacktrace. But what if...

java.lang.StackOverflowError: Exception in server tick loop
    at knot//net.minecraft.world.entity.LivingEntity.dropAllDeathLoot(LivingEntity.java)
    at knot//net.minecraft.world.entity.LivingEntity.dropAllDeathLoot(LivingEntity.java)
    at knot//net.minecraft.world.entity.LivingEntity.dropAllDeathLoot(LivingEntity.java)
    at knot//net.minecraft.world.entity.LivingEntity.dropAllDeathLoot(LivingEntity.java)
    ... (repeat 1020 more times)

Look for an @Invoker. If it's named the same, change the invoker's name.

@Mixin(LivingEntity.class)
public interface LivingEntityAccess {
    @Invoker("dropAllDeathLoot")
-   void dropAllDeathLoot( ServerLevel serverLevel, DamageSource damageSource);
+   void invokeDropAllDeathLoot(ServerLevel serverLevel, DamageSource damageSource);
}

A Codec<Pair<Thing, Something>> I made isn't working

Here's the sample:

Codec.pair(Codecs.UUID, Codec.INT).encode(Pair.of(UUID.randomUUID(), 1), NbtOps.INSTANCE, NbtOps.INSTANCE.empty());

Error:

Do not know how to append a primitive value [I;-1146627965,1080115418,-1840797042,45047876] to 1

The key part there is "a primitive value" - this is trying to serialize as

[-1146627965,1080115418,-1840797042,45047876]: 1

which is not valid JSON - an array can't be a value. You can get around this by changing the structure:

Codec.pair(Codecs.UUID.fieldOf("UUID").codec(), Codec.INT.fieldOf("int").codec());
{
  "UUID": [-1146627965,1080115418,-1840797042,45047876],
  "int": 1
}

This kind of issue ("that can't be a key, silly") can be caused other ways too (like maps with keys that don't serialize as a string).