linshenkx/prompt-optimizer · error · RequestConfigError
Invalid message role: ${msg.role}
Error message
Invalid message role: ${msg.role} What it means
Thrown by validateMessages when a message's role is not one of 'system' | 'user' | 'assistant' | 'tool'. The adapter only maps these four roles to provider formats, so anything else (e.g. 'function', 'developer', 'tool_call') is rejected client-side with a RequestConfigError that interpolates the offending role.
Source
Thrown at packages/core/src/services/llm/adapters/abstract-adapter.ts:193
* @param messages 消息数组
* @throws {RequestConfigError} 当消息数组无效时
*/
protected validateMessages(messages: Message[]): void {
if (!Array.isArray(messages)) {
throw new RequestConfigError('Messages must be an array')
}
if (messages.length === 0) {
throw new RequestConfigError('Messages array cannot be empty')
}
for (const msg of messages) {
if (!msg.role || !msg.content) {
throw new RequestConfigError('Each message must have role and content')
}
if (!['system', 'user', 'assistant', 'tool'].includes(msg.role)) {
throw new RequestConfigError(`Invalid message role: ${msg.role}`)
}
if (typeof msg.content !== 'string') {
throw new RequestConfigError('Message content must be a string')
}
}
}
protected validateImageUnderstandingRequest(request: ImageUnderstandingRequest): void {
if (!request || typeof request !== 'object') {
throw new RequestConfigError('Image understanding request cannot be empty')
}
if (typeof request.userPrompt !== 'string' || !request.userPrompt.trim()) {
throw new RequestConfigError('Image understanding user prompt cannot be empty')
}
if (!Array.isArray(request.images) || request.images.length === 0) {View on GitHub (pinned to 3e677b1d9f)
Solutions
- Remap the role to one of system/user/assistant/tool (e.g. 'function' -> 'tool')
- Fix casing and typos in role strings
- If you control the schema, constrain role with a union type so mistakes fail at compile time
Example fix
// before
messages = [{ role: 'function', content: '42' }]
// after
messages = [{ role: 'tool', content: '42' }] Defensive patterns
Strategy: type-guard
Validate before calling
const VALID = new Set(['system','user','assistant','tool'])
if (!messages.every(m => VALID.has(m.role))) throw new Error('Bad role') Type guard
const VALID_ROLES = new Set(['system','user','assistant','tool'])
function hasValidRole(m: unknown): m is Message {
return !!m && typeof m === 'object' && VALID_ROLES.has((m as Message).role)
} Try / catch
try { ... } catch (e) { if (e instanceof RequestConfigError && e.message.startsWith('Invalid message role')) { /* remap role */ } else throw e } Prevention
- Use a union type for role: 'system'|'user'|'assistant'|'tool'
- Remap legacy roles like 'function' to 'tool' when porting old OpenAI code
- Normalize casing before sending
When it happens
Trigger: Passing a message with role 'function', 'developer', 'tool_call', 'Tool' (capitalized), or any custom string; migrating code from another SDK whose role union differs.
Common situations: Porting OpenAI SDK v0 code that used role:'function'; typos or casing differences ('User'); custom agent frameworks that invent roles like 'observation'.
Related errors
- Messages array cannot be empty
- Each message must have role and content
- Message content must be a string
- Model provider metadata cannot be empty
- Model metadata cannot be empty
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/42968e1d9a53dbed.
Report an issue: GitHub.