CherryHQ/cherry-studio · error · Error

Unknown chat type: ${type}

Error message

Unknown chat type: ${type}

What it means

Thrown by QqAdapter.sendToChat() when the prefix of chatId (the part before ':') is not one of the handled cases (c2c, group, channel, dm). chatId is parsed via chatId.split(':') and the type half is switched on; an unrecognized type hits default.

Source

Thrown at src/main/ai/channels/adapters/qq/QqAdapter.ts:675

    let endpoint: string
    const body: Record<string, unknown> = { markdown: { content: text }, msg_type: 2 }

    switch (type) {
      case 'c2c':
        endpoint = `${QQ_API_BASE}/v2/users/${id}/messages`
        break
      case 'group':
        endpoint = `${QQ_API_BASE}/v2/groups/${id}/messages`
        break
      case 'channel':
        endpoint = `${QQ_API_BASE}/channels/${id}/messages`
        break
      case 'dm':
        endpoint = `${QQ_API_BASE}/dms/${id}/messages`
        break
      default:
        throw new Error(`Unknown chat type: ${type}`)
    }

    const seq = replyToMsgId ? this.nextPassiveSeq(chatId, type, replyToMsgId) : undefined
    if (seq !== undefined) {
      body.msg_id = replyToMsgId
      // v2 group/C2C dedupe repeat replies sharing one msg_id; a unique seq keeps every chunk.
      if (type === 'group' || type === 'c2c') {
        body.msg_seq = seq
      }
    }

    await this.apiRequest(endpoint, { method: 'POST', body })
  }

  /**
   * Claim the next passive-reply seq for the exact inbound message being answered, or undefined
   * to fall back to active push once the reply window has lapsed or the per-msg_id cap (5) is hit.
   * Advancing the seq keeps chunked replies from being deduped by QQ (same msg_id + msg_seq fails).

View on GitHub (pinned to 726446b54c)

Solutions

  1. Normalize all chatIds at ingestion to one of the four supported prefixes; reject others before they reach sendToChat.
  2. Validate chatId with a regex like /^(c2c|group|channel|dm):/ before sending.
  3. Add the new type as an explicit case if QQ introduces one, mapping it to the correct API path.

Example fix

// before
const [type, id] = chatId.split(':')
let endpoint: string
switch (type) {
  case 'c2c': ...
  default: throw new Error(`Unknown chat type: ${type}`)
}

// after — validate shape up front with a clearer error
const m = /^(c2c|group|channel|dm):(.+)$/.exec(chatId)
if (!m) throw new Error(`Malformed or unsupported chatId: ${chatId}`)
const [, type, id] = m
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate chatId shape before sending.
const QQ_CHAT_TYPES = ['c2c', 'group', 'channel', 'dm'] as const
type QqChatType = typeof QQ_CHAT_TYPES[number]
function parseQqChatId(chatId: string): { type: QqChatType; id: string } {
  const m = /^(c2c|group|channel|dm):(.+)$/.exec(chatId)
  if (!m) throw new Error(`Malformed QQ chatId: ${chatId}`)
  return { type: m[1] as QqChatType, id: m[2] }
}

Type guard

function isUnknownChatType(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Unknown chat type:')
}

Try / catch

try {
  await qq.sendToChat(chatId, text)
} catch (e) {
  if (isUnknownChatType(e)) { logger.error('Unsupported QQ target', { chatId }); return }
  throw e
}

Prevention

When it happens

Trigger: sendToChat(chatId, text, replyToMsgId) receives a chatId whose first segment is anything other than 'c2c','group','channel','dm' — e.g. an empty string, a typo, a chatId with no colon, or a future chat type not yet supported.

Common situations: A chatId constructed upstream with a new/unsupported prefix, a malformed chatId (missing ':'), or an inbound message routing to an unknown target type.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/2d79d2ac29fbdc78. Report an issue: GitHub.