Skip to content

Players in spectator mode can be teleported via Entity#teleport while spectating another entity, causing client-server desync #13473

@lucyydotp

Description

@lucyydotp

Expected behavior

When a player that is spectating an entity is teleported, the player stops spectating the entity, and is teleported to the location.
It would also be nice to have an option to ignore the teleport and keep the player spectating but that's for another issue.

Observed/Actual behavior

The player is teleported, but continues to spectate the entity. This breaks something most of the time, but exactly what breaks is inconsistent.

I think what happens most of the time is that the spectator is teleported, and its new location is synced with the client, but then the server-side spectator location override kicks in, which sets the player's location without syncing to the client (see nms ServerPlayer#tick), causing a nasty desync which leaves the camera in unloaded chunks. Sometimes the client can pull itself out of this state, sometimes the camera entity needs to change for it to sync up again.

Steps/models to reproduce

  • Switch to spectator mode
  • Click on an entity to start spectating it
  • While still spectating the entity, teleport yourself (but not the entity) a significant distance via Entity#teleport

I've been using this quick and dirty plugin to teleport:

package me.lucyydotp.paper_tp_bug;

import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

public class PaperTeleportBug extends JavaPlugin {
    @Override
    public void onEnable() {
        getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, c -> {
            c.registrar().register("tpbug", (source, args) -> {
                if (!(source.getExecutor() instanceof Player player)) return;
                player.teleport(player.getLocation().add(500, 0, 500));
                player.sendMessage("Teleported! New server-side location is %.3f %.3f %.3f".formatted(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ()));
            });
        });
    }
}

And a fabric mixin to see what's going on client-side (F3 shows the camera position by default): https://gist.github.com/lucyydotp/dbe1cec43e9ebd0e5f3b4d55b789bcf1

Plugin and Datapack List

None other than the above repro plugin.

Paper version

This server is running Paper version 1.21.11-69-main@94d0c97 (2025-12-30T20:33:30Z) (Implementing API version 1.21.11-R0.1-SNAPSHOT)

Other

Vanilla solves this problem by just stopping spectating on teleport (nms ServerPlayer#teleportTo), but that method isn't used by paper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: acceptedDisputed bug is accepted as valid or Feature accepted as desired to be added.version: 1.21.11Game version 1.21.11

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions