mem0ai/mem0 · warning · Error
At least one of text, metadata, timestamp, or expirationDate
Error message
At least one of text, metadata, timestamp, or expirationDate must be provided for update.
What it means
MemoryClient.update() requires at least one mutable field — text, metadata, timestamp, or expirationDate — and throws if all four are undefined. A memory update with no changes would be a no-op PATCH, so the client rejects it up front with an explicit message naming the accepted fields.
Source
Thrown at mem0-ts/src/client/mem0.ts:360
{
text,
metadata,
timestamp,
expirationDate,
}: {
text?: string;
metadata?: Record<string, any>;
timestamp?: number | string;
expirationDate?: string | null;
},
): Promise<Array<Memory>> {
if (
text === undefined &&
metadata === undefined &&
timestamp === undefined &&
expirationDate === undefined
) {
throw new Error(
"At least one of text, metadata, timestamp, or expirationDate must be provided for update.",
);
}
const payload: Record<string, any> = {};
if (text !== undefined) payload.text = text;
if (metadata !== undefined) payload.metadata = metadata;
if (timestamp !== undefined) payload.timestamp = timestamp;
if (expirationDate !== undefined) payload.expiration_date = expirationDate;
const payloadKeys = Object.keys(payload);
this._captureEvent("update", [payloadKeys]);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/${encodePathSegment(memoryId)}/`,
{
method: "PUT",
headers: this.headers,View on GitHub (pinned to 001c235229)
Solutions
- Ensure at least one field is set: client.update(id, { text: newText }).
- Guard dynamically built payloads: if (!Object.values(patch).some(v => v !== undefined)) return.
- Check field spelling — expirationDate (camelCase) maps to expiration_date in the payload; typo'd keys are silently undefined.
Example fix
// before
await client.update(memoryId, {}); // nothing to update
// after
await client.update(memoryId, { text: 'updated content' }); Defensive patterns
Strategy: validation
Validate before calling
type UpdateFields = { text?: string; metadata?: Record<string, unknown>; timestamp?: number | string; expirationDate?: string | null };
function hasAnyUpdateField(p: UpdateFields): boolean {
return p.text !== undefined || p.metadata !== undefined ||
p.timestamp !== undefined || p.expirationDate !== undefined;
}
if (!hasAnyUpdateField(patch)) return; // nothing to do — skip the call Type guard
const isUpdatePatch = (p: unknown): p is { text: string } | { metadata: Record<string, unknown> } | { timestamp: number | string } | { expirationDate: string | null } =>
typeof p === 'object' && p !== null &&
['text', 'metadata', 'timestamp', 'expirationDate'].some(k => (p as Record<string, unknown>)[k] !== undefined); Prevention
- Skip update() when a form or diff produced no changes.
- Type update payloads explicitly so typo'd keys fail typecheck.
- Remember the field is expirationDate (not expiryDate) on the client.
When it happens
Trigger: await client.update(memoryId, {}) — building the update object dynamically and every property ending up undefined (typos like `textt`, conditionals that skip all assignments, or spreading an empty source object).
Common situations: Forms where no field was edited but save was clicked; partial-update builders using conditional spreads that collapse to nothing; property-name mismatches (expiryDate vs expirationDate) leaving the payload empty.
Related errors
- Cannot process an empty messages payload.
- At least one parameter must be provided for update: custom_i
- Invalid query: cannot be empty or whitespace-only.
- Cannot update with an empty vector.
- Add requires at least one of User ID, Agent ID, Run ID, or A
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/f7ee7fb61112c936.
Report an issue: GitHub.