toeverything/AFFiNE · error · CopilotFailedToCreateMessage

copilot_failed_to_create_message

copilot_failed_to_create_message

Error message

e.message

What it means

createCopilotMessage wraps ANY failure of inbox.createMessage into CopilotFailedToCreateMessage (code `copilot_failed_to_create_message`, status `internal_server_error`), forwarding the original e.message. It is a wrapper error: the actionable cause is the message text carried inside, which comes from the inbox pipeline (session lookup, params validation, attachments, downstream providers).

Source

Thrown at packages/backend/server/src/plugins/copilot/resolver.ts:781

  @Mutation(() => String, {
    description: 'Create a chat message',
  })
  @CallMetric('ai', 'chat_message_create')
  async createCopilotMessage(
    @CurrentUser() user: CurrentUser,
    @Args({ name: 'options', type: () => CreateChatMessageInput })
    options: CreateChatMessageInput
  ): Promise<string> {
    const lockFlag = `${COPILOT_LOCKER}:message:${user?.id}:${options.sessionId}`;
    await using lock = await this.mutex.acquire(lockFlag);
    if (!lock) {
      throw new TooManyRequest('Server is busy');
    }
    try {
      return await this.inbox.createMessage(user.id, options);
    } catch (e: any) {
      throw new CopilotFailedToCreateMessage(e.message);
    }
  }

  private transformToSessionType(session: Omit<ChatHistory, 'messages'>) {
    return { id: session.sessionId, ...session };
  }
}

@Throttle()
@CopilotEnabled()
@Resolver(() => UserType)
export class UserCopilotResolver {
  constructor(private readonly ac: PermissionAccess) {}

  @ResolveField(() => CopilotType)
  async copilot(
    @CurrentUser() user: CurrentUser,
    @Args('workspaceId', { nullable: true }) workspaceId?: string

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Read the forwarded message — it names the underlying cause thrown by inbox.createMessage
  2. Verify the sessionId still exists (query copilot session history) before sending
  3. Check the attachment/params payload for size, format, and required fields
  4. Correlate with server logs for the original stack of the wrapped error (the wrapper hides trace location)

Example fix

// before
try {
  await createCopilotMessage({ variables: { options } });
} catch (e) {
  toast('Failed'); // underlying cause lost
}

// after
try {
  await createCopilotMessage({ variables: { options } });
} catch (e) {
  const cause = (e as GraphQLError)?.extensions?.code === 'copilot_failed_to_create_message'
    ? (e as Error).message // server forwarded inbox error text
    : 'Failed to send';
  toast(cause);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// guard: verify the session exists and the payload is sane before sending
const sessions = await fetchCopilotSessions(workspaceId);
if (!sessions.some(s => s.id === options.sessionId)) {
  throw new Error('session missing — recreate before sending');
}
if (options.attachments?.some(a => a.size > MAX_ATTACHMENT_BYTES)) {
  throw new Error('attachment too large');
}

Type guard

function isFailedToCreateMessage(e: unknown): boolean {
  return (e as { extensions?: { code?: string } })?.extensions?.code === 'copilot_failed_to_create_message';
}

Try / catch

try {
  return await createCopilotMessage({ variables: { options } });
} catch (e) {
  if (isFailedToCreateMessage(e)) {
    // e.message carries the forwarded inbox error — surface it, do not blind-retry
    reportToUser((e as Error).message);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: inbox.createMessage throws: the sessionId no longer exists, message params/attachments fail validation, the workspace's AI provider or DB rejects the request, or a downstream prompt/runtime error occurred while enqueueing the message.

Common situations: Sending into a session deleted by cleanup; oversized or malformed attachments; provider credentials/quota issues surfacing at message-create time; custom inbox code paths that throw plain Errors.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/ef5a619e99d0f923. Report an issue: GitHub.