Five Bedrock add-on bugs that fail without an error
An invisible horse, legs running four times too fast, a mob that forgot how to jump, and a magic pack that broke without being touched. Five Minecraft Bedrock add-on bugs I hit building LLS Equestrian and the Magic Pack, and how to catch them.
The worst bugs in a Bedrock add-on aren’t the ones that crash. They’re the ones where the game carries on as if nothing happened: no error on screen, no crash, just a mob that’s gone invisible or a feature that quietly stopped working. Here are five I hit while building LLS Equestrian and the Magic Pack, what each looked like, and how I catch them now.
If you’re a player rather than a modder, the one thing to take from this: when an add-on misbehaves, switch on the Content Log (Settings → Creator). Every one of these leaves a trace there, and nowhere else. There’s a guide to reading it.
1. math.max with three arguments makes the whole mob invisible
What happened: after adding a new jump animation, every horse in the world went invisible. So did the horse spawn egg. Every item from the same pack still showed fine.
The cause: one animation line used math.max(a, b, c). Molang’s maths functions take
a fixed number of arguments: math.max takes exactly two. With three, Bedrock logs
“Unexpected number of parameters… expected 2, found 3” and throws out the entire
client entity: model, textures, animations and the egg icon with it.
Why it got past me: I build the animations with a script, and it previews them by
translating Molang to JavaScript. JavaScript’s Math.max takes any number of arguments,
so the preview ran perfectly.
The fix: nest the calls, math.max(math.max(a, b), c). The build script now checks
the argument count of every Molang function call before it writes anything.
2. Reading a variable before it’s set stops everything after it
What happened: some horses rendered pink, some invisible, and the game lagged badly. The Content Log was scrolling thousands of “unknown variable” errors a second.
The cause: in an entity’s pre_animation script, one line read a variable that was
only set further down. On Bedrock, reading an unset variable doesn’t give you zero: it
raises an error that stops the rest of the script, every frame. So every variable
after that line was never set, including the one that picks the coat texture. No texture
index meant the pink “missing texture” colour.
Why it got past me: in JavaScript a missing value is just undefined. And a test run
skipped the line, because it sat behind a condition (the horse lying down) that the test
never met.
The fix: any variable read above the line that sets it needs a starting value in
initialize. The build now checks this statically: it walks the lines in the order the
game runs them (initialize, then pre_animation, then the animations) and refuses to
build if anything is read before it’s written.
Tip: when you see a flood of “unknown variable” errors, find the variable that’s set earliest in the script. The broken line is just above it.
3. modified_distance_moved isn’t in blocks
What happened: in previews, the walk and trot looked right. In game, the legs went like a sewing machine. I counted six head bobs to a real horse’s one or two. Every “make it slower” change I tried made the previews wrong and barely touched the game.
The cause: the stride was timed off q.modified_distance_moved, as if it counted
blocks travelled. It doesn’t. It’s vanilla’s limb-swing counter: it runs at about four
times the distance moved and caps at 20 per second, which it hits at about five
blocks a second. So the walk and trot were running four times too fast, and the canter
and gallop about twice (because of the cap).
Why it got past me: the previews fed the animation the real speed, not what the game actually reports. Preview and game silently disagreed.
The fix: time stride-locked animation from q.ground_speed, which really is blocks
per second. The bigger lesson: an offline preview has to simulate the game’s own
numbers the way the game produces them, odd scaling included, or it will look right
while the game looks wrong.
4. Removing a component group deletes things it didn’t add
What happened: horses that had never worn a work harness lost their jump after lying down, rolling or being brushed. Leaving and rejoining the world brought it back.
The cause: in a Bedrock entity file, component groups are added on top of each other, but removing one deletes every component it names, outright. It doesn’t fall back to the version in the base components, or in another group that’s still active.
The “lie down” event’s remove list included the work-harness group “just in case”. That group sets jump strength to zero, so it names the jump component. Removing it removed the horse’s jump, whether the horse had ever been harnessed or not. Rejoining fixed it only because a script re-applies jump strength on load.
The fix:
- Keep each shared component in exactly one group at a time.
- Swap groups in one event: remove the old and add the new together.
- Never put a group on a remove list “just in case”. Removing a group a mob doesn’t have still deletes the components it names.
5. An update you didn’t make breaks a pack you didn’t touch
What happened: the Magic Pack was finished and working. A few days later the frost staff stopped hitting anything, healing checks always failed, and knockback stopped completely. Nobody had changed a line of its code.
The cause: the Magic Pack ships as one combined pack built from several mods, and the combined pack runs all of their scripts under one version of Bedrock’s scripting API, the highest any of them asks for. When another mod in the bundle moved to version 2.x, the older magic code started running under 2.x too. Two things changed in 2.0:
isValidwent from a method to a property. Callingentity.isValid()now throws “not a function”.applyKnockback(dirX, dirZ, strength, up)changed shape toapplyKnockback({ x, z }, up). The old form throws.
Both calls were wrapped in try/catch, so instead of crashing the features just
stopped. The log had 170,000 “not a function” lines from the frost staff alone.
The fix: a small compatibility file with alive() and knockback() helpers that
work under both versions. And a rule: after raising the scripting version of anything
in a bundle, search the Content Log for not a function and the older code for
.isValid() and applyKnockback(.
The pattern
All five have the same shape: something that checks my work agreed with me, and the
game didn’t. A preview in JavaScript, a test that skipped a branch, a try/catch
that swallowed an error. What catches them:
- Read the Content Log after every change, not only when something breaks.
- Make previews and tests behave like the game, including its strict and strange parts.
- Check statically what you can. Argument counts and read-before-set are both caught before a single file is written now.
The horses all of this went into are in LLS Equestrian, and the staves in the Magic Pack. Both are free downloads for Bedrock.
The mods
LLS Equestrian
Riding horses that feel alive - eleven breeds, real gaits and coat genetics, show tack, breeding, care and training.
LLS Magic Pack
Elemental spellcasting you have to aim, two companions worth keeping, and hand-built dungeons guarded by statues that aren't.
More from the devlog
- Making it snow on a plains farm: faking winter weather in Minecraft Bedrock Bedrock has no snow weather and decides rain-or-snow from the biome. How LLS Seasons builds a snowy day from fog, a particle and a snow carpet of its own, and the summer freeze a snow sweep caused.
- Making a gate swing in Minecraft Bedrock, when blocks can't animate Bedrock blocks can't move, and a custom block's collision has to fit inside one block. How the double-wide gates in LLS Missing Blocks fake both, and the collision tricks that keep a cow in and let a horse through.
- Paws that stay planted: two-bone IK in Molang for the Doggoyle How the Doggoyle in the LLS Magic Pack keeps its paws on the ground at a walk, trot and gallop: a stride clock from ground speed, footfalls planned on the floor, and inverse kinematics solved every frame in Bedrock's Molang.