mem0ai/mem0 · warning · NodeOperationError

Provide text or metadata to update

Error message

Provide text or metadata to update

What it means

DELETE /api-keys/{key_id} parses key_id as a UUID; anything that is not a valid UUID string raises 404 (not 422) from the except branch. This intentionally makes malformed IDs indistinguishable from missing keys so the endpoint does not leak which key IDs exist.

Source

Thrown at integrations/n8n-nodes-mem0/nodes/Mem0/Mem0.node.ts:550

					const memoryId = this.getNodeParameter('memoryId', i) as string;
					responseData = await request('GET', `/v1/memories/${encodeURIComponent(memoryId)}/`);
				} else if (operation === 'update') {
					const memoryId = this.getNodeParameter('memoryId', i) as string;
					const body: IDataObject = {};
					const text = this.getNodeParameter('text', i, '') as string;
					const metadata = this.getNodeParameter('metadata', i, '') as string;
					if (text) body.text = text;
					if (metadata) {
						try {
							body.metadata = typeof metadata === 'string' ? JSON.parse(metadata) : metadata;
						} catch {
							throw new NodeOperationError(this.getNode(), 'Invalid JSON in "Metadata" field', {
								itemIndex: i,
							});
						}
					}
					if (Object.keys(body).length === 0) {
						throw new NodeOperationError(this.getNode(), 'Provide text or metadata to update', {
							itemIndex: i,
						});
					}
					responseData = await request('PUT', `/v1/memories/${encodeURIComponent(memoryId)}/`, body);
				} else if (operation === 'delete') {
					const memoryId = this.getNodeParameter('memoryId', i) as string;
					responseData = await request('DELETE', `/v1/memories/${encodeURIComponent(memoryId)}/`);
				}

				const arr = Array.isArray(responseData) ? responseData : [responseData];
				for (const entry of arr) {
					returnData.push({ json: entry, pairedItem: { item: i } });
				}
			} catch (error) {
				if (this.continueOnFail()) {
					returnData.push({ json: { error: (error as Error).message }, pairedItem: { item: i } });
					continue;
				}

View on GitHub (pinned to 001c235229)

Solutions

  1. Use the id field from the POST /api-keys creation response or GET /api-keys listing (a full UUID like '3fa85f64-5717-4562-b3fc-2c963f66afa6').
  2. Validate client-side that key_id matches a UUID pattern before issuing the DELETE.
  3. If your stored id is shorter, you saved the wrong field — re-fetch the key list.

Example fix

# before
requests.delete(f"{BASE}/api-keys/{key_prefix}", headers=h)  # 404

# after
keys = requests.get(f"{BASE}/api-keys", headers=h).json()
key_id = next(k["id"] for k in keys if k["label"] == "ci-bot")
requests.delete(f"{BASE}/api-keys/{key_id}", headers=h)
Defensive patterns

Strategy: type-guard

Validate before calling

import uuid

def is_uuid(value: str) -> bool:
    try:
        uuid.UUID(value)
        return True
    except (TypeError, ValueError):
        return False

assert is_uuid(key_id), f"key_id must be a UUID, got {key_id!r}"

Type guard

def is_key_id(value: str) -> bool:
    """True when value is a valid UUID string usable as an API key id."""
    try:
        uuid.UUID(str(value))
        return True
    except (TypeError, ValueError):
        return False

Prevention

When it happens

Trigger: Calling DELETE /api-keys/my-key, /api-keys/123, or with a truncated UUID (35 chars); passing the key prefix or the raw API key value instead of the key record's id; URL-encoding issues that mangle the UUID.

Common situations: Confusing the key's id (returned in the listing/creation response) with the key material or its prefix; hand-building the URL and dropping a character; frontend storing label instead of id.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/cad85ae77d291ce0. Report an issue: GitHub.