mastra-ai/mastra · error · MastraError
DATASET_ITEM_EXTERNAL_ID_INVALID
DATASET_ITEM_EXTERNAL_ID_INVALID
Error message
Dataset item externalId must be a non-empty string.
What it means
validateDatasetItemExternalId() (a MastraError with id DATASET_ITEM_EXTERNAL_ID_INVALID, domain STORAGE, category USER) rejects an items' externalId of exactly '' (empty string). Undefined/absent externalId is allowed (auto-generated id is used), but an explicit empty string is treated as a caller bug since externalIds are identity keys.
Source
Thrown at packages/core/src/storage/domains/datasets/identity.ts:132
} satisfies DatasetItemRow;
if (!datasetItemPayloadsEqual(item, acceptedRow)) {
conflicts.push({ index, externalId: item.externalId, existingItemId: local.id, reason: 'payload_mismatch' });
}
resolvedIds.push(local.id);
continue;
}
const insert = { id: createId(), item };
inserts.push(insert);
requestLocal.set(item.externalId, insert);
resolvedIds.push(insert.id);
}
if (conflicts.length) throw createDatasetItemIdentityConflictError(conflicts);
return { inserts, resolvedIds, existingCurrentItems };
}
export function validateDatasetItemExternalId(externalId: string | undefined): void {
if (externalId === '') {
throw new MastraError({
id: 'DATASET_ITEM_EXTERNAL_ID_INVALID',
text: 'Dataset item externalId must be a non-empty string.',
domain: 'STORAGE',
category: 'USER',
});
}
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Omit externalId entirely when you have none, so the library generates an id.
- Generate a real externalId before inserting (e.g. crypto.randomUUID() or a domain key).
- Validate/coerce input upstream: trim and reject blank keys before building the batch.
- Note that undefined passes but '' throws — normalize '' to undefined, never to a placeholder string.
Example fix
// before
await storage.datasets.addItems({ datasetId: 'ds', items: [{ externalId: row.key || '', input: row.data }] });
// after
const externalId = row.key?.trim() || undefined; // undefined -> generated id
await storage.datasets.addItems({ datasetId: 'ds', items: [{ externalId, input: row.data }] }); Defensive patterns
Strategy: validation
Validate before calling
for (const item of items) {
if (item.externalId === '') throw new Error(`items[${items.indexOf(item)}].externalId must be non-empty or omitted`);
} Type guard
function hasValidExternalId(item: { externalId?: string }): boolean {
return item.externalId === undefined || item.externalId.length > 0;
} Try / catch
try {
await storage.datasets.addItems({ datasetId, items });
} catch (e) {
if (e?.id === 'DATASET_ITEM_EXTERNAL_ID_INVALID') {
// report the offending payload to the caller / fix upstream input
} else throw e;
} Prevention
- Trim and normalize key fields at the ingestion boundary; convert '' to undefined.
- Use generated ids (omit externalId) unless you have a real domain key.
- Add a schema check on imports (CSV/JSON) that rejects blank key columns.
When it happens
Trigger: addItems()/batchInsertItems() with an item like {externalId: '', input, ...} — typically externalId sourced from an empty form field, empty request property, or `String(value)` of null/'' upstream.
Common situations: Importing rows from CSV/spreadsheets where a key column is blank, copying user input straight into externalId, or template code that defaults `externalId: something || ''`.
Related errors
- DATASET_INVALID_ID
- COMPARE_INVALID_INPUT
- Dataset not found: ${args.id}
- SchemaUpdateValidationError
- [FilesystemStorage] resourceId must not be empty.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/75fd0883bd863014.
Report an issue: GitHub.