Skip to content

@Persist state returns RpcStub objects when returned via RPC #99

@dmmulroy

Description

@dmmulroy

Problem

When an Actor method returns @Persist decorated state via RPC, the caller receives RpcStub objects instead of serialized data.

Reproduction

https://github.com/dmmulroy/actor-bug

git clone https://github.com/dmmulroy/actor-bug
cd actor-bug
npm install
npm run dev
curl http://localhost:8787

DataActor.ts

import { Actor, Persist } from "@cloudflare/actors";

type Item = { id: string; value: number };

export class DataActor extends Actor<Env> {
  @Persist state: { items: Item[] } = { items: [] };

  async getItems(): Promise<Item[]> {
    return this.state.items; // Returns RpcStub objects to RPC callers
  }
}

CoordinatorActor.ts (RPC caller)

const dataActor = DataActor.get("data-1");
const items = await dataActor.getItems();

console.log(items);           // [ RpcStub {}, RpcStub {} ]
console.log(typeof items[0]); // "function"
console.log(String(items[0])); // "[object JsRpcStub]"

Expected

getItems() returns [{ id: "item-1", value: 100 }, ...]

Actual

getItems() returns [RpcStub {}, RpcStub {}] which serialize to [null, null]

Workarounds

1. Query storage directly (recommended)

async getItems(): Promise<Item[]> {
  const result = this.ctx.storage.sql.exec(
    "SELECT value FROM _actor_persist WHERE property = 'state'"
  );
  const row = [...result][0];
  if (row) {
    return JSON.parse(row.value as string).items ?? [];
  }
  return [];
}

2. JSON roundtrip

async getItems(): Promise<Item[]> {
  return JSON.parse(JSON.stringify(this.state.items));
}

Environment

  • @cloudflare/actors: 0.0.1-beta.6
  • wrangler: 4.53.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions