---
title: "DF0020: Non-JSON Value in JSON-Serializable RPC"
description: "RPC function \"{name}\" declares jsonSerializable: true but the value at \"{path}\" is a {type}."
canonical_url: "https://devfra.me/errors/df0020"
---
# DF0020: Non-JSON Value in JSON-Serializable RPC

> RPC function "\{name}" declares jsonSerializable: true but the value at "\{path}" is a \{type}.

## Message

> RPC function "`{name}`" declares `jsonSerializable: true` but the value at "`{path}`" is a `{type}`.

## Cause

A `jsonSerializable: true` function encodes its args and return value with strict `JSON.stringify` (on the wire and in build dumps). The serializer throws at the offending value rather than emit a corrupt payload when it hits anything JSON cannot round-trip losslessly:

- `Map`, `Set`, `WeakMap`, `WeakSet`
- `Date` (JSON coerces it to an ISO string)
- `BigInt`, `Symbol`, `Function`
- circular references
- non-plain class instances
- `undefined` leaves

## Example

```ts
defineRpcFunction({
  name: 'my-plugin:graph',
  jsonSerializable: true,
  handler: () => ({
    nodes: new Map([
      ['a', 1]
    ]), // ✗ throws DF0020: type=Map, path="nodes"
  }),
})
```

## Fix

Drop `jsonSerializable: true` to fall back to `structured-clone-es` (round-trips `Map`, `Set`, etc.), or convert the payload to a JSON-safe shape before returning. Keeping `agent` exposure requires the JSON-safe shape.

## Source

- [`packages/devframe/src/rpc/serialization.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/rpc/serialization.ts): the strict JSON serializer throws `DF0020` (with the offending path and runtime type) when a `jsonSerializable: true` payload contains a non-JSON value.


## Sitemap

See the full [sitemap](https://devfra.me/sitemap.md) for all pages.
