Skip to main content
Manage Actors

Fork Actor

Create a new actor whose database is a copy of another actor's, and start it. The new actor has the source's name and pool, a new ID, and the key you give it.

The copy holds every write the source committed before the call, like a crash point: state the source still holds in memory is not included, so call saveState({ immediate: true }) in an action first to include it. The new actor runs onFork once at its first start instead of createState and onCreate. Both actors keep the copied schedule, queue and workflows, so each runs them. A fork is not idempotent: a key already held answers actor.duplicate_key. A database can be forked at most 16 times deep. The call answers once the copy finished. If its 30 second deadline passes after the new actor was created, it answers actor.fork_pending (504) with the new actor’s ID in metadata.actor_id; the copy goes on, so read that actor later instead of forking again. If the deadline passes before the create was confirmed, it answers 500 core.internal_error with no actor ID, and the create may still land: retrying a keyless fork can then make a second copy, while retrying a keyed fork answers actor.duplicate_key. A source that never started has no database to copy and answers actor.fork_failed without creating anything. A namespace token needs fork on the source actor, by its ID or any, and create on every actor (any), since the new actor’s ID is not known before the fork. The copy hands the caller everything the source holds, so no other operation, including read, allows a fork. The fork input comes from the caller: validate it in onFork like any client input. While an engine upgrade is rolling out, forks are refused with actor.fork_unavailable (503 with Retry-After) until every engine worker supports them; retry after the hinted delay. In a namespace upgraded from an earlier release, a keyed source that the upgrade has not yet moved into its namespace’s volume group is refused with guard.service_unavailable (503 with Retry-After, reason actor_moving), since the move gives it a new actor ID that the copy’s forked_from must name; retry after the hinted delay, and the fork is admitted once the source has moved.

POST https://rivet.example.com/actors/{actor_id}/fork

Examples

Authentication

Send your namespace token as a bearer token in the Authorization header. Every control plane request also requires the namespace query parameter. See Authentication.

Path Parameters

NameTypeRequiredDescription
actor_idstringYesID of the actor.

Query Parameters

NameTypeRequiredDescription
namespacestringNoName of the namespace to operate in.

Request Body

Content type: application/json.

FieldTypeRequiredDescription
keystring | nullNoKey of the new actor. Multi-part keys are joined with /, see Actor Keys. Omit for a keyless actor.
inputstring | nullNoBase64-encoded CBOR fork input, passed to the new actor’s onFork hook. It comes from the caller, so onFork must validate it like any client input.

Responses

200

The new actor, once its database copy finished. actor.forked_from names the source.

FieldTypeDescription
actorobject
actor.actor_idstringUnique ID of the actor.
actor.namestringActor name as registered in your RivetKit registry.
actor.keystringActor key. Multi-part keys are joined with /, see Actor Keys.
actor.namespacestringName of the namespace the actor belongs to.
actor.poolstringName of the node pool the actor runs in.
actor.create_tsintegerWhen the actor was created, in Unix milliseconds.
actor.start_tsinteger | nullWhen the actor first started. Not recorded by this version, so always null.
actor.pending_allocation_tsinteger | nullWhen the actor started waiting for a node. Not recorded by this version, so always null.
actor.connectable_tsinteger | nullWhen the actor last became connectable. Not recorded by this version, so always null.
actor.sleep_tsinteger | nullWhen the actor went to sleep. Not recorded by this version, so always null.
actor.reschedule_tsinteger | nullWhen the actor will next try to allocate. Not recorded by this version, so always null.
actor.destroy_tsinteger | nullWhen the actor was destroyed, in Unix milliseconds. Only set in listings that include destroyed actors; otherwise null.
actor.forked_fromany | null | stringID of the actor this actor’s database was forked from, or null.
{
  "actor": {
    "actor_id": "d97pbq1nyqxw1w5qdwz0iirbqiblh2",
    "name": "my-actor",
    "key": "my-key",
    "namespace": "my-namespace",
    "pool": "default",
    "create_ts": 1700000000000,
    "start_ts": null,
    "pending_allocation_ts": null,
    "connectable_ts": null,
    "sleep_ts": null,
    "reschedule_ts": null,
    "destroy_ts": null,
    "forked_from": null
  }
}

400

actor.invalid_key: key is longer than 1024 bytes. actor.invalid_key_encoding: key is not in canonical slash-separated form. actor.key_owned_elsewhere: another datacenter owns the key. envoy.invalid_namespace_name: the namespace value is not a DNS label of 1 to 63 lowercase letters, digits and hyphens. actor.invalid_input: input is not valid base64.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "actor",
  "code": "invalid_name",
  "message": "Actor name must be 1 to 64 bytes."
}

401

auth.invalid_token: the request carries no token, or the token is not valid. auth.token_expired: the token has expired.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "auth",
  "code": "invalid_token",
  "message": "Authentication token is invalid."
}

403

auth.insufficient_permissions: the token’s grants do not allow forking the source actor and creating actors, or for a namespace token the source actor does not exist. A namespace token needs fork on the source actor (its ID or any) and create on every actor (any), since the new actor’s ID is not known before the fork. No other operation, including read, allows a fork.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "auth",
  "code": "insufficient_permissions",
  "message": "Insufficient permissions to access this resource."
}

404

actor.not_found: the source actor does not exist, was destroyed, or belongs to another namespace. namespace.not_found: the namespace does not exist.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "actor",
  "code": "not_found",
  "message": "The actor does not exist or was destroyed."
}

409

actor.duplicate_key: a live actor already holds key, including an earlier fork of the same source. Forks are not idempotent. actor.fork_too_deep: the source’s database is already 16 forks deep. actor.fork_failed: the database copy failed, for example because the source was destroyed during the fork, and the new actor was destroyed; or the source never started, so it has no database to copy, and nothing was created. namespace.pending, namespace.archived: the namespace does not accept new actors.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "actor",
  "code": "fork_too_deep",
  "message": "The actor is too many forks deep to fork again."
}

415

The request is missing the Content-Type: application/json header. Returned as plain text.

Content type: text/plain.

422

The JSON body does not match the request schema, for example a missing required field, a wrong type or an unknown field where unknown fields are rejected. Returned as plain text.

Content type: text/plain.

500

core.internal_error: an unexpected failure, including a request whose 30 second deadline passed before the new actor was created.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "core",
  "code": "internal_error",
  "message": "An internal error occurred"
}

503

auth.verification_unavailable: token verification keys are temporarily unavailable. Retry the request. actor.fork_unavailable: an engine upgrade is rolling out and not every engine worker supports forks yet. Nothing was created; retry after the Retry-After delay. guard.service_unavailable (reason actor_moving): in a namespace upgraded from an earlier release, the keyed source has not yet been moved into its namespace’s volume group, which gives it a new ID. Nothing was created; retry after the Retry-After delay.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "auth",
  "code": "verification_unavailable",
  "message": "The server could not verify the authentication token because verification keys are temporarily unavailable. Retry the request."
}

504

actor.fork_pending: the request’s 30 second deadline passed after the new actor was created, while its database copy goes on. metadata.actor_id names the new actor: read it with GET /actors/{actor_id} later. It starts once the copy finishes, or is destroyed if the copy fails. Do not send the fork again, since forks are not idempotent.

FieldTypeDescription
groupstringError group, for example actor.
codestringError code within the group, for example not_found.
messagestringHuman-readable error message.
metadataanyExtra details on some errors, for example the retry hint of a refusal or the new actor of a pending fork.
{
  "group": "actor",
  "code": "fork_pending",
  "message": "The actor fork is still in progress; read actor 0yu3yi42e4nqf61brlp3pmqnc7xu00 later.",
  "metadata": {
    "actor_id": "0yu3yi42e4nqf61brlp3pmqnc7xu00"
  }
}
Edit this page Last updated November 12, 2026