Skip to content

[Bug] claude_code_only 误拦截官方 Claude Code 的 count_tokens 和 stream=false /v1/messages 请求 #2909

@WesleyZiwen

Description

@WesleyZiwen

问题描述

开启分组的 claude_code_only 限制后,官方 Claude Code 客户端发出的部分请求会被误判为非 Claude Code 客户端,导致账号选择阶段失败:

this group only allows Claude Code clients

受影响的请求主要包括:

  • POST /v1/messages/count_tokens
  • 部分 POST /v1/messagesstream=false 的请求

这些请求来自官方 Claude Code CLI,而不是第三方客户端。

环境信息

  • Claude Code CLI: 2.1.156 (Claude Code)
  • npm package: @anthropic-ai/claude-code@2.1.156
  • sub2api upstream main checked at: f18451e56f15b31ef602ab238037b56c3522b19f
  • 分组配置:claude_code_only=true
  • 模型示例:claude-opus-4-8

已对比本地代码和 upstream main,以下关键文件/逻辑与 upstream main 一致,排除了本地 fork 修改导致的问题:

  • backend/internal/service/claude_code_validator.go
  • backend/internal/handler/gateway_helper.go
  • backend/internal/handler/gateway_handler.go
  • backend/internal/service/gateway_service.goresolveGatewayGroup / checkClaudeCodeRestriction 相关片段

观察到的现象

在同一段 Claude Code 官方 CLI 会话中:

  • stream=true/v1/messages 请求可以正常识别并转发
  • /v1/messages/count_tokens 请求会在账号选择前失败
  • 部分 stream=false/v1/messages 请求也会在账号选择前失败
  • 服务端日志报错为 this group only allows Claude Code clients

失败发生在 sub2api 的账号选择阶段,因此这些失败请求没有被转发到上游 Anthropic。

代码路径分析

当前 ClaudeCodeValidator.Validate() 中的路径判断是:

path := r.URL.Path
if !strings.Contains(path, "messages") {
    return true
}

因此 /v1/messages/count_tokens 会因为路径包含 messages 而进入 messages 严格校验逻辑。

同时 CountTokens() 中也会调用:

SetClaudeCodeClientContext(c, body, parsedReq)

SetClaudeCodeClientContext() 对包含 messages 的路径会继续调用 claudeCodeValidator.Validate(c.Request, bodyMap)

如果官方 Claude Code 的 count_tokens 请求或部分内部 stream=false 请求不携带完整 messages 请求中的 system prompt / headers / metadata 形态,就会被判定为 IsClaudeCodeClient(ctx)=false,随后在 claude_code_only 分组中触发:

if !group.ClaudeCodeOnly || IsClaudeCodeClient(ctx) {
    return group, &currentID, nil
}

if group.FallbackGroupID == nil {
    return nil, nil, ErrClaudeCodeOnly
}

期望行为

官方 Claude Code CLI 发出的辅助请求不应被 claude_code_only 误拦截,尤其是:

  • /v1/messages/count_tokens
  • 官方 CLI 内部产生的 stream=false /v1/messages 请求

这些请求应该可以基于已确认的 Claude Code UA / CLI 请求特征通过,或至少不要因为缺少完整主请求 system prompt 而被当作非 Claude Code 客户端。

实际行为

开启 claude_code_only 后,上述官方 Claude Code 请求会被误判,导致返回 503,服务端日志中显示:

gateway.count_tokens_select_account_failed ... error=this group only allows Claude Code clients
gateway.select_account_no_available ... error=this group only allows Claude Code clients

可能的修复方向

建议考虑对 /v1/messages/count_tokens 单独处理,例如不要套用完整 /v1/messages 的 system prompt 严格校验,或者为官方 Claude Code 的 count_tokens / 内部辅助请求增加兼容分支。

对于 stream=false /v1/messages,可能也需要确认官方 Claude Code 在某些内部请求场景下是否不会携带完整主请求特征,避免误判。

补充说明

这个问题与本地 fork 修改无关:已将相关识别和分组限制代码与 upstream main 对比,关键逻辑一致。

相关历史问题看起来与此类似:#917#1926#1111#248

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions