mastra-ai/mastra · error · HTTPException
DATASET_ITEM_EXTERNAL_ID_INVALID
DATASET_ITEM_EXTERNAL_ID_INVALID
Error message
error.message (DATASET_ITEM_EXTERNAL_ID_INVALID, cause: field externalId)
What it means
When an item's externalId fails validation (wrong type, empty, or otherwise invalid per DATASET_ITEM_EXTERNAL_ID_INVALID), the handler maps the MastraError to HTTP 400 with cause: { field: 'externalId' }, pointing the caller at the offending field.
Source
Thrown at packages/server/src/server/handlers/datasets.ts:1229
items: items.map(item => ({ ...item, externalId: item.externalId ?? undefined })),
});
return { items: addedItems, count: addedItems.length };
} catch (error) {
if (isSchemaValidationError(error)) {
throw new HTTPException(400, {
message: error.message,
cause: { field: error.field, errors: error.errors },
});
}
if (error instanceof MastraError) {
if (error.id === 'DATASET_ITEM_IDENTITY_CONFLICT') {
throw new HTTPException(409, {
message: error.message,
cause: { conflicts: 'conflicts' in error ? error.conflicts : [] },
});
}
if (error.id === 'DATASET_ITEM_EXTERNAL_ID_INVALID') {
throw new HTTPException(400, { message: error.message, cause: { field: 'externalId' } });
}
throw new HTTPException(getHttpStatusForMastraError(error.id) as StatusCode, { message: error.message });
}
return handleError(error, 'Error batch inserting items');
}
},
});
export const BATCH_DELETE_ITEMS_ROUTE = createRoute({
method: 'DELETE',
path: '/datasets/:datasetId/items/batch',
responseType: 'json',
pathParamSchema: datasetIdPathParams,
bodySchema: batchDeleteItemsBodySchema,
responseSchema: batchDeleteItemsResponseSchema,
summary: 'Batch delete items from dataset',
description: 'Deletes multiple items from the dataset in a single operation (single version entry)',
tags: ['Datasets'],View on GitHub (pinned to 75dd419e61)
Solutions
- Coerce externalId to a non-empty string (or omit it entirely) for every item in the batch.
- Normalize null to undefined before sending: externalId: item.externalId ?? undefined.
- Validate each item's externalId client-side before the request.
- Check upstream data sources for numeric or whitespace-only IDs and trim/cast them.
Example fix
// before
items: [{ externalId: 12345, input }]
// after
items: [{ externalId: String(12345), input }] Defensive patterns
Strategy: validation
Validate before calling
function isValidExternalId(v: unknown): boolean {
return v === undefined || (typeof v === 'string' && v.trim().length > 0);
}
items.forEach(i => {
if (!isValidExternalId(i.externalId)) throw new Error(`Invalid externalId: ${JSON.stringify(i.externalId)}`);
if (i.externalId === null) delete i.externalId; // send undefined, not null
}); Type guard
function hasValidExternalId(item: { externalId?: unknown }): item is { externalId?: string } {
return item.externalId === undefined ||
(typeof item.externalId === 'string' && item.externalId.trim().length > 0);
} Try / catch
try {
return await batchInsertItems(datasetId, items);
} catch (err) {
if (err.status === 400 && err.body?.cause?.field === 'externalId') {
console.error('externalId rejected; coercing and retrying once');
const fixed = items.map(i => ({ ...i, externalId: i.externalId == null ? undefined : String(i.externalId) }));
return batchInsertItems(datasetId, fixed);
}
throw err;
} Prevention
- Coerce numeric external IDs with String() at the boundary with external systems.
- Omit externalId entirely instead of sending null when absent.
- Add a shared normalize step for batch payloads (trim, stringify, drop empties).
- Type externalId as string | undefined (not string | null | number) in client code.
When it happens
Trigger: POST /datasets/:datasetId/items/batch with an item whose externalId is not a valid string (e.g. a number, null leaked explicitly, empty string, or an object) — note the handler normalizes undefined to undefined, but explicit nulls/other types can trip storage validation.
Common situations: Passing numeric IDs from an external system without String() conversion; sending null instead of omitting the field; copying items between datasets where externalId types differ; form data coercing values incorrectly.
Related errors
- error.message (schema validation error, cause: field/errors)
- bad request: ${responseText}
- COMPARE_INVALID_INPUT
- SchemaValidationError(field, this.formatErrors(result.error)
- DATASET_INVALID_ID
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ab28cf67fefe1a2c.
Report an issue: GitHub.