tinyhumansai/openhuman · error
RPC envelope contains undefined data
Error message
RPC envelope contains undefined data
What it means
Thrown by unwrapEnvelope() in threadApi: the response is an object that HAS a 'data' key, but its value is undefined. Crucially, JSON serialization cannot carry undefined — a real HTTP JSON-RPC body never produces this — so the envelope was constructed in JavaScript, not parsed from the wire. It almost always indicts a mock or an in-process wrapper that adds {data: ...} unconditionally.
Source
Thrown at app/src/services/api/threadApi.ts:40
ListTurnStatesResponse,
PersistedTurnState,
PutTaskBoardResponse,
RunEvent,
RunEventListResponse,
TaskBoard,
TaskBoardCard,
} from '../../types/turnState';
import { callCoreRpc } from '../coreRpcClient';
interface Envelope<T> {
data?: T;
}
function unwrapEnvelope<T>(response: Envelope<T> | T): T {
if (response && typeof response === 'object' && 'data' in response) {
const envelope = response as Envelope<T>;
if (envelope.data === undefined) {
throw new Error('RPC envelope contains undefined data');
}
return envelope.data;
}
return response as T;
}
const generateTitleLog = debug('threadApi.generateTitleIfNeeded');
export const threadApi = {
createNewThread: async (labels?: string[]): Promise<Thread> => {
const response = await callCoreRpc<Envelope<Thread>>({
method: 'openhuman.threads_create_new',
params: { labels },
});
return unwrapEnvelope(response);
},
getThreads: async (): Promise<ThreadsListData> => {View on GitHub (pinned to a221052e0d)
Solutions
- Reproduce under Vitest and inspect which method's mock resolves {data: undefined} — this error is nearly always test/mock-originated
- Fix the mock to either omit the data key entirely or provide a real value: mockResolvedValue(threadFixture), not {data: undefined}
- Audit any wrapper on the callCoreRpc path that spreads or rebuilds {data: ...} without checking the source value
- Verify against the real core (curl the /rpc method) to confirm the wire shape is fine
Example fix
// before (test)
mockRpc.mockResolvedValue({ data: undefined });
// after (test)
mockRpc.mockResolvedValue(threadFixture); // no envelope at all Defensive patterns
Strategy: type-guard
Validate before calling
// In wrappers: only build an envelope when a value actually exists
return value !== undefined ? { data: value } : ({} as Envelope<T>); Type guard
function hasDefinedData<T>(v: unknown): v is { data: T } {
return !!v && typeof v === 'object' && 'data' in v && (v as { data: unknown }).data !== undefined;
} Try / catch
try {
const thread = await threadApi.createNewThread(labels);
} catch (e) {
if (e instanceof Error && e.message.includes('undefined data')) {
// In-memory envelope bug (mock/wrapper) — not a wire failure; fix the producer
flagMockOrWrapperBug(e);
} else throw e;
} Prevention
- Never mock RPC envelopes as {data: undefined} — omit the key or return the bare value
- Remember JSON cannot encode undefined: this error always means JS-constructed data
- Type mockResolvedValue against the real response type so TS catches missing fixtures
When it happens
Trigger: A Vitest mock of callCoreRpc resolving {data: undefined} for threads_create_new / other thread methods; a transport or caching wrapper that builds {data: value} even when value is undefined; code doing response = { data: response.data } on a response lacking data.
Common situations: Test suites with partially-specified mocks (the mock author wrote {data: someFixture} where someFixture was undefined); a refactor introducing an envelope-spreading wrapper on the RPC path; a stale service worker / dev shim fabricating responses.
Related errors
- threads_token_usage returned an empty envelope
- provider_surfaces_list_queue: unexpected empty response
- Invalid ${paramName}: '${value}'. Must be a valid integer ID
- Invalid ${paramName}: ${String(value)}. Type must be an inte
- Model test RPC returned no result for ${workload} via ${prov
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/dd94586b22045af2.
Report an issue: GitHub.