OptionalabortOptionalacceptDefines which Content-Type values are accepted when this handler is invoked via the ingress.
Wildcards are supported, for example application/* or * / *.
If unset, input.contentType will be used as the default.
This setting does not affect deserialization. To customize how the input is deserialized,
provide an input Serde.
OptionalasBy default, Restate treats errors as terminal (non-retryable) only when they are instances of TerminalError.
Use this hook to map domain-specific errors to TerminalError (or return undefined to keep them retryable).
When mapped to TerminalError, the error will not be retried.
Note: This applies to errors thrown inside ctx.run closures as well as errors thrown by Restate handlers.
Example:
class MyValidationError extends Error {}
const greeter = restate.service({
name: "greeter",
handlers: {
greet: async (ctx: restate.Context, name: string) => {
if (name.length === 0) {
throw new MyValidationError("Length too short");
}
return `Hello ${name}`;
}
},
options: {
asTerminalError: (err) => {
if (err instanceof MyValidationError) {
// My validation error is terminal
return new restate.TerminalError(err.message, { errorCode: 400 });
}
// Any other error is retryable
}
}
});
OptionaldescriptionHuman-readable description of the handler, shown in documentation/admin tools.
Optional ExperimentalexplicitWhen set to true, the SDK will stop automatically propagating cancellations when awaiting RestatePromises.
Instead, the user code must explicitly listen to cancellations using the ctx.cancellation() API in ContextInternal.
OptionalhooksHooks providers for this handler. Handler-level hooks wrap innermost —
they run after service-level hooks. Both levels are merged: service
hooks first, then handler hooks. Within each level, hooks execute in
array order: for [A, B]: A before → B before → handler → B after → A after.
The handler interceptor fires on every attempt. The run interceptor
fires only when the ctx.run() closure actually executes — replayed
runs (already in the journal) are skipped.
Errors thrown at any point (before or after next()) affect the invocation:
TerminalError fails immediately, any other error triggers a retry.
On suspension or pause, next() also rejects — do any cleanup and rethrow.
const myService = restate.service({
name: "MyService",
handlers: {
greet: restate.createServiceHandler(
{
hooks: [
(ctx) => ({
interceptor: {
handler: async (next) => {
console.log(`before ${ctx.request.target}`);
try {
await next();
console.log(`after ${ctx.request.target}`);
} catch (e) {
console.log(`error ${ctx.request.target}: ${e}`);
// Always rethrow — swallowing the error changes the
// invocation outcome. You can also throw a different
// error (e.g. TerminalError to fail immediately).
throw e;
}
},
run: async (name, next) => {
console.log(` before run "${name}"`);
try {
await next();
console.log(` after run "${name}"`);
} catch (e) {
console.log(` error run "${name}": ${e}`);
throw e;
}
},
},
}),
],
},
async (ctx, name) => `Hello, ${name}!`
),
},
});
OptionalidempotencyThe retention duration of idempotent requests to this handler.
Note: Available only when registering this endpoint with restate-server v1.4 or newer; otherwise service discovery will fail.
OptionalinactivityGuards against stalled invocations. Once this timeout expires, Restate requests a graceful suspension of the invocation (preserving intermediate progress).
If the invocation does not react to the suspension request, abortTimeout is used to abort it.
Overrides the inactivity timeout set at the service level and the default configured in the Restate server.
Note: Available only when registering this endpoint with restate-server v1.4 or newer; otherwise service discovery will fail.
OptionalingressWhen set to true, this handler cannot be invoked via the Restate server HTTP or Kafka ingress;
it can only be called from other services.
Note: Available only when registering this endpoint with restate-server v1.4 or newer; otherwise service discovery will fail.
OptionalinputSerde used to deserialize the input parameter.
Defaults to restate.serde.json.
Provide a custom Serde if the input is not JSON, or use
restate.serde.binary to skip serialization/deserialization altogether;
in that case the input parameter is a Uint8Array.
OptionaljournalThe journal retention for invocations to this handler.
When a request has an idempotency key, idempotencyRetention caps the journal retention time.
Note: Available only when registering this endpoint with restate-server v1.4 or newer; otherwise service discovery will fail.
OptionalmetadataArbitrary key/value metadata for the handler. Exposed via the Admin API.
OptionaloutputSerde used to serialize the output value.
Defaults to restate.serde.json.
Provide a custom Serde if the output is not JSON, or use
restate.serde.binary to skip serialization/deserialization altogether;
in that case the output value is a Uint8Array.
OptionalretryRetry policy to apply to all requests to this handler. For each unspecified field, the default value configured in the service or, if absent, in the restate-server configuration file, will be applied instead.
OptionalserdeDefault serde to use for requests, responses, state, side effects, awakeables, promises. Used when no other serde is specified.
If not provided, defaults to serde.json.
The input or output of this handler can be overridden using the input/output fields
Guards against invocations that fail to terminate after inactivity. The abort timeout starts after
inactivityTimeoutexpires and a graceful termination was requested. When this timer expires, the invocation is aborted.This timer may interrupt user code. If more time is needed for graceful termination, increase this value.
Overrides the abort timeout set at the service level and the default configured in the Restate server.
Note: Available only when registering this endpoint with restate-server v1.4 or newer; otherwise service discovery will fail.