Why jumping on the tick you are hit cancels your knockback. The cancellation is a blend formula in the movement code; the strict "late is fine, early fails" timing is an artifact of how the result travels back to you over the network as an overwrite.
Two layers, two questions. The movement code explains why a sprint-jump cancels knockback. The netcode explains when you have to do it.
When you are hit, LivingEntity.knockback sets your new horizontal velocity to oldVelocity / 2 − knockback. It blends, it does not replace. So velocity you already carry toward the attacker is halved and then subtracted from the knockback that pushes you away. A sprint-jump injects a burst of velocity in your look direction — straight at the enemy — so when the blend folds it in, most of the horizontal knockback cancels and you keep your ground. That is the mechanism, and it is entirely in vanilla movement code.
But in multiplayer the hit is resolved on the server, and the result is shipped back to you as a velocity packet that overwrites your local motion. That single fact — overwrite, not blend, applied after a network delay — is why you can jump on time or late but never early: anything you do before the packet lands is discarded by the overwrite, and anything after it survives. The timing window you feel is the shape of that round trip.
All code is decompiled Minecraft from the multi-version tree on disk: modern snippets are Mojang-mapped (the knockback$v1_17_0 variant spans 1.17 through 26.x, covering the affected 1.19.3 / 1.20.6); 1.8.9 snippets are MCP-named. Decompiler artifacts are lightly cleaned, logic untouched. Where a claim rests on architecture rather than a line I could open, it is flagged.
The bug as Mojang records it.
| Field | Value |
|---|---|
| Key / Summary | MC-259487 — Jumping just as you're attacked allows you to take little to no horizontal knockback |
| Status | Open ● unresolved · Confirmation: Community Consensus |
| Affects | 1.19.323w04a1.20.624w44a |
| Duplicated by | MC-278103 Jumping can reset player's velocity · MC-272128 Vertical/reduced knockback when hit while jumping |
Verbatim: "While sprinting forward, when you press your jump key at the same time when you get attacked, you will take reduced/no horizontal knockback depending on how accurately you time it." Both halves are load-bearing in the code below: it requires sprinting forward (the forward velocity does the cancelling) and it is timing- and ping-dependent (the jump must align with how the hit is registered and sent back).
The single line the whole exploit rests on, in LivingEntity.knockback.
// net/minecraft/world/entity/LivingEntity.java — knockback$v1_17_0 (1.17 → 26.x) public void knockback(double strength, double x, double z) { strength *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); if (!(strength <= 0.0)) { this.needsSync = true; // mark velocity dirty → server will sync it Vec3 dm = this.getDeltaMovement(); // your CURRENT velocity Vec3 kb = new Vec3(x, 0.0, z).normalize().scale(strength); this.setDeltaMovement( dm.x / 2.0 - kb.x, // horizontal: HALVE old, then subtract knockback this.onGround() ? Math.min(0.4, dm.y / 2.0 + strength) : dm.y, dm.z / 2.0 - kb.z); // same on Z } }
The horizontal result is not −kb; it is dm/2 − kb. Your pre-hit velocity is a first-class input to the knockback you receive. If dm.x points toward the attacker (the negative of the knockback direction), it cancels into kb.x and the magnitude collapses. The faster you are already moving into the hit, the less knockback you take. Note the needsSync = true: this same call flags your velocity dirty, which is what later sends it across the wire in §6.
Jumping is not only vertical. While sprinting it adds a horizontal burst in your look direction — and in a duel you are looking straight at the enemy.
// LivingEntity.java — jumpFromGround() public void jumpFromGround() { float jumpPower = this.getJumpPower(); // 0.42 at baseline if (!(jumpPower <= 1.0E-5F)) { Vec3 v = this.getDeltaMovement(); this.setDeltaMovement(v.x, Math.max(jumpPower, v.y), v.z); if (this.isSprinting()) { float yaw = this.getYRot() * 0.017453292F; // degrees → radians this.addDeltaMovement(new Vec3(-Mth.sin(yaw) * 0.2, 0.0, Mth.cos(yaw) * 0.2)); } // +0.2 in the facing direction } }
The sprint clause adds 0.2 of horizontal speed pointed where you face. Stack it on normal sprint momentum (~0.28/tick) and, on the jump tick, dm toward the attacker peaks near 0.48. Feed that into dm/2 − kb and the subtraction nearly zeroes out. The jump also sets v.y to the jump power, so the vertical survives — hence "you popped up but barely moved back."
Stand still and jump, and dm.x ≈ 0, so dm.x/2 − kb.x ≈ −kb.x — full knockback. The cancellation comes entirely from your forward velocity; the jump's job is to spike that velocity at the decisive moment. No forward sprint, no reset.
In singleplayer there is no packet. The hit and your jump are resolved in the same tick, and the in-tick order is the whole story — which is why the window here is only a tick or two.
this.jumping && onGround && noJumpDelay == 0, call jumpFromGround() — injecting the forward burst into deltaMovement.knockback() — dm/2 − kb — folding your freshly-spiked forward velocity into the result.travel() applies movement and friction (airborne ≈ 0.91/tick, ground ≈ 0.55). With horizontal already small, what remains decays.For the blend to cancel, your forward velocity has to be present in dm at the instant knockback() runs. With everything local and same-tick, that alignment is narrow — the one-or-two-tick window players describe offline. Multiplayer is where it widens, and where the asymmetry appears.
In PvP the hit is resolved on the server and pushed to you as a velocity packet. How that packet is applied is the hinge of the entire timing model.
Your movement is client-authoritative: every tick your client simulates your player (§5) and reports the resulting position to the server, which trusts it within anti-cheat limits. Knockback is the exception — it originates server-side. The server runs knockback() on its copy of you, the needsSync flag from §3 marks your motion dirty, and the entity tracker sends you a ClientboundSetEntityMotionPacket. When it arrives, your client applies it:
// net/minecraft/world/entity/Entity.java — lerpMotion(), invoked by the SetEntityMotion packet public void lerpMotion(double x, double y, double z) { this.setDeltaMovement(x, y, z); // a hard SET — your current velocity is DISCARDED, not blended }
That is the crux. The server's blend already happened with the server's view of your velocity; what reaches your client is an absolute value that replaces your local motion wholesale. So there are two distinct moments — the server resolving the hit, and your client overwriting — separated by your latency:
knockback() blends dm/2 − kb on the server's copy of you and flags your motion dirty.SetEntityMotion back to you. It does not arrive instantly.lerpMotion → setDeltaMovement replaces your local velocity with the server's knockback. Everything you did before this instant is gone.The overwrite plus client authority produce a one-sided window: velocity created before the packet is erased, velocity created after it survives.
If your jump fires before the packet lands, your forward burst moves you and is reported — then SetEntityMotion arrives and setDeltaMovement overwrites it with the server's full knockback. Your work is discarded and you eat the whole hit. This is why an early jump does not just fail to help, it fails: there is nothing your pre-hit velocity can do that the overwrite will not erase.
Once the overwrite has landed, your local velocity is the knockback, and authority is yours again. A jump now re-injects the +0.2 forward boost, and holding W keeps travel() adding forward acceleration each tick, cutting the residual backward velocity before it carries you far. A jump on the exact overwrite tick is the "0-tick" perfect reset; later jumps still help while the backward velocity is large.
The window has a width for two compounding reasons. First, latency shifts the clock: the packet may not reach you until several ticks after the server's hit tick, so "late on the server's clock" is "on time on yours" — more ping, wider window. Second, the knockback decays slowly: airborne friction is ~0.91/tick, so the backward velocity persists for several ticks during which re-adding forward still meaningfully cuts displacement. Past roughly that span the knockback has already moved you and re-jumping stops mattering. A reported ~6-tick ceiling reads as the ping window plus those few still-cancellable ticks.
Players cite two windows: ~1–2 ticks and ~6 ticks. That is the same mechanism in its two regimes. Singleplayer has no packet and no overwrite, so it is the pure same-tick blend of §5 (tight). Multiplayer layers the overwrite-plus-latency window on top (wider, and one-sided). The window literally grows with latency — which is the tell that the timing is a netcode artifact, not part of the knockback math.
Verified directly in source: the server-side blend (dm/2 − kb + needsSync) and the client-side overwrite (lerpMotion → setDeltaMovement). Reasoned from architecture, not a line opened here: the packet's exact send timing, and whether the server's dm term reflects your live forward velocity at hit-time (the part that makes a "0-tick" jump cancel server-side too). Strictly, "never early" is a multiplayer/overwrite rule; in a pure local blend, a hair-early jump could still help.
Plugging illustrative numbers into dm.x/2 − kb.x with a base knockback of 0.4. Positive = toward attacker, negative = pushed back.
| Forward velocity dm.x at the blend | Horizontal result | Effect |
|---|---|---|
Standing still · 0 | 0/2 − 0.4 = −0.40 | Full knockback ● flung back |
Sprinting in · ≈ 0.28 | 0.28/2 − 0.4 = −0.26 | Reduced ("w-tapping") ● partial |
Sprint-jump aligned · ≈ 0.48 | 0.48/2 − 0.4 = −0.16 | Mostly cancelled ● holds ground |
Magnitudes are illustrative (base strength 0.4; sprint speed and the +0.2 boost approximate). The trend is the point: the larger your forward velocity when the blend runs, the smaller the surviving knockback.
The blend is ancient, which is why jump-resetting predates the report by a decade.
// 1.8.9 net/minecraft/entity/EntityLivingBase.java — knockBack() this.motionX /= 2.0; this.motionY /= 2.0; this.motionZ /= 2.0; // same halving this.motionX -= var3 / var7 * 0.4; // same subtract this.motionY += 0.4; // vertical pop is UNCONDITIONAL this.motionZ -= var5 / var7 * 0.4; if (this.motionY > 0.4) this.motionY = 0.4;
1.8.9 halves-and-subtracts exactly like modern, so the horizontal reset works identically. The only difference is vertical: 1.8.9 always adds the 0.4 pop, whereas modern gates it on onGround (this.onGround() ? Math.min(0.4, dm.y/2 + strength) : dm.y). So since 1.17 a hit taken while airborne also skips the upward launch. That is a secondary sweetener; the shared, load-bearing cause across every affected version is the horizontal blend.
The behavior is two vanilla methods plus the netcode that connects them.
Resolving MC-259487 means changing LivingEntity.knockback (stop blending the victim's own velocity into horizontal knockback, or clamp it), jumpFromGround (don't inject horizontal velocity that can oppose a simultaneous hit), or how knockback is reconciled between server and client (the overwrite is what hands players the late window). All three are core systems Mojang owns. The ticket sits at Open / Community Consensus because the behavior is load-bearing competitive tech: any of those changes alters how every PvP hit feels, so it is a balance decision as much as a code one.
| Vanilla method / field | Class | Role in the bug |
|---|---|---|
knockback(...) (knockback$v1_17_0) | LivingEntity | The dm/2 − kb blend — root cause; sets needsSync |
jumpFromGround() | LivingEntity | Injects 0.42 up + 0.2 forward sprint burst |
aiStep() | LivingEntity | Runs jump before travel — sets the same-tick window |
lerpMotion() → setDeltaMovement() | Entity | Velocity packet OVERWRITES local motion — source of the early/late asymmetry |
needsSync / markHurt() | Entity | Dirty flag that triggers the server→client velocity packet |
travelInAir(...) | LivingEntity | Air (0.91) vs ground (~0.55) friction — how the result decays |
knockBack(...) / jump() | EntityLivingBase (1.8.9) | Same blend; vertical pop unconditional |
Sources: Mojira MC-259487 (description + comments, bugs.mojang.com API) · decompiled Minecraft — LivingEntity.java & Entity.java (modern, mojmap), EntityLivingBase.java (1.8.9, MCP) · Minecraft Wiki, Knockback (mechanic). Server packet timing reasoned from architecture; velocity magnitudes illustrative.