mastra-ai/mastra · error
Invalid ${kind}: ${name}. Must start with a letter or unders
Error message
Invalid ${kind}: ${name}. Must start with a letter or underscore, contain only letters, numbers, or underscores, and be at most 63 characters long. What it means
`parseSqlIdentifier` validates SQL table/column/index names against `SQL_IDENTIFIER_PATTERN` (start with letter or underscore, only letters/numbers/underscores) and a 63-character limit (PostgreSQL identifier max). It throws this error to prevent SQL injection and to surface names that would be truncated or require quoting by the storage layer.
Source
Thrown at packages/core/src/utils.ts:595
/**
* Parses and returns a valid SQL identifier (such as a table or column name).
* The identifier must:
* - Start with a letter (a-z, A-Z) or underscore (_)
* - Contain only letters, numbers, or underscores
* - Be at most 63 characters long
*
* @param name - The identifier string to parse.
* @param kind - Optional label for error messages (e.g., 'table name').
* @returns The validated identifier as a branded type.
* @throws {Error} If the identifier does not conform to SQL naming rules.
*
* @example
* const id = parseSqlIdentifier('my_table'); // Ok
* parseSqlIdentifier('123table'); // Throws error
*/
export function parseSqlIdentifier(name: string, kind = 'identifier'): SqlIdentifier {
if (!SQL_IDENTIFIER_PATTERN.test(name) || name.length > 63) {
throw new Error(
`Invalid ${kind}: ${name}. Must start with a letter or underscore, contain only letters, numbers, or underscores, and be at most 63 characters long.`,
);
}
return name as SqlIdentifier;
}
/**
* Parses and returns a valid dot-separated SQL field key (e.g., 'user.profile.name').
* Each segment must:
* - Start with a letter (a-z, A-Z) or underscore (_)
* - Contain only letters, numbers, or underscores
* - Be at most 63 characters long
*
* @param key - The dot-separated field key string to parse.
* @returns The validated field key as a branded type.
* @throws {Error} If any segment of the key is invalid.
*
* @exampleView on GitHub (pinned to 75dd419e61)
Solutions
- Rename the identifier to match `[A-Za-z_][A-Za-z0-9_]{0,62}` — replace dashes/dots/spaces with underscores.
- Truncate or hash long names to stay under 63 characters (e.g. prefix + short hash).
- Sanitize dynamic names before calling the API: `name.replace(/[^A-Za-z0-9_]/g, '_')` and assert length.
- Use Mastra's configuration options (e.g. table name prefixes) that produce compliant names instead of raw user input.
Example fix
// before
const table = `mastra-${tenantSlug}_traces`; // dashes from slug
// after
const table = `mastra_${tenantSlug.replace(/[^A-Za-z0-9_]/g, '_')}_traces`; Defensive patterns
Strategy: validation
Validate before calling
const SQL_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
function assertSqlIdentifier(name: string, kind = 'identifier') {
if (!SQL_IDENTIFIER_PATTERN.test(name) || name.length > 63)
throw new Error(`Invalid ${kind}: ${name}`);
} Type guard
function isSqlIdentifier(name: string): name is `${string}` {
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) && name.length <= 63;
} Try / catch
let table: SqlIdentifier;
try {
table = parseSqlIdentifier(rawTableName, 'table');
} catch (e) {
throw new Error(`Configured table name "${rawTableName}" is invalid: ${(e as Error).message}`);
} Prevention
- Derive dynamic table names with `raw.replace(/[^A-Za-z0-9_]/g, '_')` and cap length.
- Avoid hyphens/dots/spaces in env-driven prefixes and tenant slugs used in table names.
- Keep generated index names under 63 chars — truncate long prefixes and append a short hash.
When it happens
Trigger: Passing a table name, column name, conflict column, or index name to a storage/DB adapter API (e.g. `parsedTableName`, `parsedColumn`, `parsedIndexName` callers) containing hyphens, dots, spaces, unicode, quotes, or a name longer than 63 chars; dynamic table names derived from user input or environment values like a prefixed `MASTRA_*` scope.
Common situations: Naming storage tables after tenant/product slugs with dashes (`my-app_agents`); auto-generating index names that exceed 63 chars due to long prefixes; interpolated table names from env vars containing invalid characters.
Related errors
- Invalid Code Mode external identifier: ${externalName}
- Field key cannot be empty
- Invalid field key segment: ${segment} in ${key}
- ClaudeSDKAgent resumeData must include sessionId or continue
- CursorSDKAgent resumeData must include a message.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1d71bc1c8356a8cf.
Report an issue: GitHub.