Skip to content

TS Client: "ERROR: Negative reference count for row", and "ERROR: Updating a row that was not present in the cache" #2894

@doodlechaos

Description

@doodlechaos

TS Client Version: "@clockworklabs/spacetimedb-sdk": "^1.2.0",
spacetimedb = "1.2.0"

How to reproduce:
Create fresh rust server and paste this into lib.rs.

use spacetimedb::{rand::Rng, reducer, table, ReducerContext, ScheduleAt, Table, TimeDuration};

#[table(name = player, public, 
    index(name = idx_dummy, btree(columns = [dummy]))
 )]
#[derive(Clone)]
pub struct Player {
    #[primary_key]
    pub player_id: u64,

    pub dummy: u64,
    pub x: i32,
}

#[table(name = player_data, public, 
    index(name = idx_dummy, btree(columns =[dummy]))
 )]
pub struct PlayerData {
    #[primary_key]
    pub player_id: u64,

    pub dummy: u64,
    pub y: i32,
}

#[reducer(init)]
pub fn init(_ctx: &ReducerContext) -> Result<(), String> {
    let _ = _ctx.db.player().try_insert(Player {
        player_id: 1,
        dummy: 0,
        x: 0,
    });

    let _ = _ctx.db.player_data().try_insert(PlayerData {
        player_id: 1,
        dummy: 0,
        y: 0,
    });

    let _ = _ctx.db.player().try_insert(Player {
        player_id: 2,
        dummy: 0,
        x: 0,
    });

    let _ = _ctx.db.player_data().try_insert(PlayerData {
        player_id: 2,
        dummy: 0,
        y: 0,
    });

    init_tick_players_schedule(_ctx);

    Ok(())
}

#[table(name = move_players_schedule, scheduled(tick_players))]
pub struct MovePlayersSchedule {
    #[primary_key]
    #[auto_inc]
    pub id: u64,

    pub scheduled_at: ScheduleAt,
}

pub fn init_tick_players_schedule(ctx: &ReducerContext) {
    let scheduled_at = TimeDuration::from_micros(1000000).into();

    let schedule = ctx
        .db
        .move_players_schedule()
        .iter()
        .next()
        .unwrap_or_else(|| {
            ctx.db.move_players_schedule().insert(MovePlayersSchedule {
                id: 0,
                scheduled_at,
            })
        });

    ctx.db
        .move_players_schedule()
        .id()
        .update(MovePlayersSchedule {
            id: schedule.id,
            scheduled_at,
        });
}

#[reducer]
pub fn tick_players(ctx: &ReducerContext, _args: MovePlayersSchedule) -> Result<(), String> {

    let player1 = ctx.db.player().player_id().find(1).unwrap();

    ctx.db.player().player_id().update(Player {
        x: ctx.rng().gen_range(0..10),
        ..player1
    });

    ctx.db.player_data().player_id().update(PlayerData {
        player_id: player1.player_id,
        dummy: 0,
        y: ctx.rng().gen_range(0..10),
    });

    let player2 = ctx.db.player().player_id().find(2).unwrap();

    ctx.db.player().player_id().update(Player {
        x: ctx.rng().gen_range(0..10),
        ..player2
    });

    ctx.db.player_data().player_id().update(PlayerData {
        player_id: player2.player_id,
        dummy: 0,
        y: ctx.rng().gen_range(0..10),
    });

    Ok(())
}

Create fresh ts client:
Subscribe to the player table with these queries:

function App() {
  const [count, setCount] = useState(0)

  const [connected, setConnected] = useState<boolean>(false);
  const [identity, setIdentity] = useState<Identity | null>(null);
  const [conn, setConn] = useState<DbConnection | null>(null);

  useEffect(() => {
    const subscribeToQueries = (conn: DbConnection, queries: string[]) => {
      conn
        ?.subscriptionBuilder()
        .onError((err) => {
          console.error('Error subscribing to queries:', err);
        })
        .onApplied(() => {
          console.log('SDK client cache initialized. (Done subscribing to queries)');

          conn.db.player.onUpdate((player) => {
            console.log('Player updated:', player);
          });
        })
        .subscribe(queries);
    };

    const onConnect = (
      conn: DbConnection,
      identity: Identity,
      token: string
    ) => {
      setIdentity(identity);
      setConnected(true);
      localStorage.setItem('auth_token', token);
      console.log(
        'Connected to SpacetimeDB with identity:',
        identity.toHexString()
      );

      subscribeToQueries(conn, [
        `SELECT * FROM player_data`,

        `SELECT p.* 
        FROM player p
        JOIN player_data d ON p.dummy = d.dummy
        WHERE d.player_id = 2
          AND p.x < d.y`
      ]);
    };

Open the debug log and you'll see these errors randomly about once every 5 seconds as the server ticks.
Image

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions