Porting and maintaining multiple versions of a mod can be a lot of work. Sometimes things slip through the cracks. One of those things were the Lepidopterist’s trade offers. I didn’t notice until after release that the Lepidopterist wasn’t offering all the trades they were supposed to.
So this bug has been around for a few versions. But today, I finally fixed it.
Finding the Problem
I first noticed the issue while playing on 1.21.4 in my own forever world. I came across a Lepidopterist selling only a Butterfly Net and nothing else.

That’s not right. Villagers are meant to have at least two trades at their starting level. I didn’t have time to look into it then, so I made a ticket and moved on.
Later, I revisited the issue in a test world. The problem was consistent: every Lepidopterist spawned with just the net for sale. After levelling them up I found that they offered no new trades at all. Clearly something was broken.
Digging into the Code
My mod registers new trades by responding to the VillagerTradesEvent
. Normally, this works fine. But in 1.21.4, this event is triggered before the ServerAboutToStartEvent
. At that point, the Butterfly Data isn’t loaded.
That’s a problem.
Without the Butterfly Data, the trade system has nothing to work with—no species, types, or rarities. But I’d solved a similar issue before when porting to 1.18.2, so I knew what to do: generate the required data ahead of time in code.
Code Generation
I already use the Python script to generate an array of Species in code, that can then be used without the Butterfly Data being loaded. All I had to do was extend that code generation function to include Butterfly Types and Rarities too.
Here’s a snippet of the updated Python code that generates the ButterflyType
array:
# Start of the array definition. output_file.write(""" // A list of types of butterflies. public static final ButterflyData.ButterflyType[] TYPES = { """) # Iterate over all butterflies, moths, and specials for butterfly in all: folders = [BUTTERFLIES_FOLDER, MALE_BUTTERFLIES_FOLDER, MOTHS_FOLDER, MALE_MOTHS_FOLDER, SPECIAL_FOLDER] type = None i = 0 # Check all folders while type is None and i < len(folders): folder = folders[i] try: # Try and open the file with open(BUTTERFLY_DATA + folder + butterfly + ".json", 'r', encoding="utf8") as input_file: json_data = json.load(input_file) # Pull out the type if an exception wasn't thrown type = json_data["type"] # If file not found, ignore the error and move on to the next folder except FileNotFoundError: # doesn't exist pass else: # exists pass i = i + 1 # Write out the Butterfly Type output_file.write(""" ButterflyData.ButterflyType.""" + type.upper() + """, """) # Finish defining the array output_file.write(""" }; """)
I do the same for Rarities as well. This means we now have access to the required data before any events are fired.
Updating the Event Handler
With the data generated up front, I updated the VillagerTradesEvent
handler to use the static arrays instead of querying dynamic data:
for (int i = 0; i < ButterflySpeciesList.SPECIES.length; ++i) { if (ButterflySpeciesList.TYPES[i] != ButterflyData.ButterflyType.SPECIAL) { switch (ButterflySpeciesList.RARITIES[i]) { case COMMON: // Add trades here break; case UNCOMMON: // Add trades here break; case RARE: // Add trades here break; } } }
After implementing this, I loaded into the game to test. Sure enough, Lepidopterists now have trades again!
So, if you’re playing the mod in 1.21.4, you can finally get a collection of butterfly-related items from these villagers.
Next
There are still a few more bugs to squash before I get back to adding new features. Fixing bugs like this is worthwhile. Each one teaches you something new, and it makes future versions of the mod that much more robust.
Keep your foundations strong, and anything you build on top will be more stable.