NEWS LETTER

claude_code_installation

Scroll down

新版claude code变化:

1
2
3
4
5
6
7
● API Error: 400 1 validation error:
{'type': 'literal_error', 'loc': ('body', 'messages', 1, 'role'), 'msg': "Input should be 'user' or 'assistant'", 'input': 'system', 'ctx': {'expected': "'user' or
'assistant'"}}

File "/usr/local/lib/python3.12/dist-packages/vllm/entrypoints/utils.py", line 48, in create_messages
POST /v1/messages [{'type': 'literal_error', 'loc': ('body', 'messages', 1, 'role'), 'msg': "Input should be 'user' or 'assistant'", 'input': 'system', 'ctx':
{'expected': "'user' or 'assistant'"}}]

这是 Claude Code v2.1.154+ 的已知回归问题(regression)。该版本开始将 system 角色放入 messages 数组内部,而 vLLM 的 Anthropic 兼容层只接受 userassistant 两种角色,导致 400 校验错误。


问题根因

Anthropic Messages API 的标准做法是将系统提示放在顶层 system 字段,而非 messages 数组中。但 Claude Code v2.1.154+ 在对话过程中会将 system 角色作为消息数组的一员发送(通常出现在 messages[1] 位置),这导致:

  • vLLMcreate_messages 校验失败(只认 user/assistant
  • OllamaDeepSeekSenseNova 等兼容端点同样报错
  • VS Code 插件版受影响,CLI 旧版本正常

解决方案(按推荐顺序)

方案一:回退 Claude Code 并禁用自动更新(最快)

1
2
3
4
5
6
7
8
# 卸载当前版本
npm uninstall -g @anthropic-ai/claude-code

# 安装最后一个正常版本 v2.1.153
npm install -g @anthropic-ai/claude-code@2.1.153

# 禁用自动更新(必须,否则会自动升级回问题版本)
export CLAUDE_CODE_DISABLE_AUTOUPDATER=1

或在 VS Code 的 settings.json 中:

1
2
3
4
5
{
"env": {
"CLAUDE_CODE_DISABLE_AUTOUPDATER": "1"
}
}

注意:v2.1.154 是为了支持 Opus 4.8 而引入的,如果你不需要 Opus 4.8,回退到 v2.1.153 是完全安全的。

方案二:在 vLLM 侧添加请求转换(如果你控制 vLLM 服务)

在 vLLM 的入口或代理层拦截请求,将 messages 数组中的 role: "system" 提取出来,合并到顶层 system 字段,并从 messages 中删除。这是 Anthropic 官方推荐的标准格式。

方案三:等待上游修复


补充说明

  • 该问题与项目目录或 CLAUDE.md 内容无关,是 Claude Code 全局请求格式的变更。
  • 如果你使用的是 VS Code 插件,插件会自动更新到最新版,因此即使 CLI 回退了,插件仍可能报错,需要在插件设置中关闭自动更新或安装特定旧版本。

claude code新的安装方式

基于npm的安装方案已经是deprecated,但是新版的curl方案又会被Anthotropic封禁IP,导致无法下载,因此需要使用代理进行下载。 首先开启代理转发,如ssh -f -N -T -R 26890:localhost:14184 h20_dockerssh -f -N -T -R 26890:localhost:14184 -p 20001 -J sshjump wangzongwu@172.16.0.163, 随后使用以下脚本进行安装(对官方脚本进行适当优化):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/bin/bash

set -e

export http_proxy=http://127.0.0.1:26890
export http_proxy=https://127.0.0.1:26890

# Parse command line arguments
TARGET="$1" # Optional target parameter

# Validate target if provided
if [[ -n "$TARGET" ]] && [[ ! "$TARGET" =~ ^(stable|latest|[0-9]+\.[0-9]+\.[0-9]+(-[^[:space:]]+)?)$ ]]; then
echo "Usage: $0 [stable|latest|VERSION]" >&2
exit 1
fi

DOWNLOAD_BASE_URL="https://downloads.claude.ai/claude-code-releases"
DOWNLOAD_DIR="$HOME/.claude/downloads"

# Check for required dependencies
DOWNLOADER=""
if command -v curl >/dev/null 2>&1; then
DOWNLOADER="curl"
elif command -v wget >/dev/null 2>&1; then
DOWNLOADER="wget"
else
echo "Either curl or wget is required but neither is installed" >&2
exit 1
fi

# Check if jq is available (optional)
HAS_JQ=false
if command -v jq >/dev/null 2>&1; then
HAS_JQ=true
fi

# Download function that works with both curl and wget
# download_file() {
# local url="$1"
# local output="$2"

# if [ "$DOWNLOADER" = "curl" ]; then
# if [ -n "$output" ]; then
# curl -fsSL -o "$output" "$url"
# else
# curl -fsSL "$url"
# fi
# elif [ "$DOWNLOADER" = "wget" ]; then
# if [ -n "$output" ]; then
# wget -q -O "$output" "$url"
# else
# wget -q -O - "$url"
# fi
# else
# return 1
# fi
# }
download_file() {
local url="$1"
local output="$2"

if [ "$DOWNLOADER" = "curl" ]; then
if [ -n "$output" ]; then
curl -fL -# -o "$output" "$url"
else
curl -fL -# "$url"
fi
elif [ "$DOWNLOADER" = "wget" ]; then
if [ -n "$output" ]; then
wget --show-progress -O "$output" "$url"
else
wget -q -O - "$url"
fi
else
return 1
fi
}

# Simple JSON parser for extracting checksum when jq is not available
get_checksum_from_manifest() {
local json="$1"
local platform="$2"

# Normalize JSON to single line and extract checksum
json=$(echo "$json" | tr -d '\n\r\t' | sed 's/ \+/ /g')

# Extract checksum for platform using bash regex
if [[ $json =~ \"$platform\"[^}]*\"checksum\"[[:space:]]*:[[:space:]]*\"([a-f0-9]{64})\" ]]; then
echo "${BASH_REMATCH[1]}"
return 0
fi

return 1
}

# Detect platform
case "$(uname -s)" in
Darwin) os="darwin" ;;
Linux) os="linux" ;;
MINGW*|MSYS*|CYGWIN*) echo "Windows is not supported by this script. See https://code.claude.com/docs for installation options." >&2; exit 1 ;;
*) echo "Unsupported operating system: $(uname -s). See https://code.claude.com/docs for supported platforms." >&2; exit 1 ;;
esac

case "$(uname -m)" in
x86_64|amd64) arch="x64" ;;
arm64|aarch64) arch="arm64" ;;
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac

# Detect Rosetta 2 on macOS: if the shell is running as x64 under Rosetta on an ARM Mac,
# download the native arm64 binary instead of the x64 one
if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then
if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then
arch="arm64"
fi
fi

# Check for musl on Linux and adjust platform accordingly
if [ "$os" = "linux" ]; then
if [ -f /lib/libc.musl-x86_64.so.1 ] || [ -f /lib/libc.musl-aarch64.so.1 ] || ldd /bin/ls 2>&1 | grep -q musl; then
platform="linux-${arch}-musl"
else
platform="linux-${arch}"
fi
else
platform="${os}-${arch}"
fi
mkdir -p "$DOWNLOAD_DIR"

# Always download latest version (which has the most up-to-date installer)
# version=$(download_file "$DOWNLOAD_BASE_URL/latest")
if [ -n "$TARGET" ] && [[ "$TARGET" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
version="$TARGET"
else
version=$(download_file "$DOWNLOAD_BASE_URL/latest")
fi

echo "Detected platform: $platform"
echo "Latest version: $version"

# Reject non-version content (e.g. an HTML error page) before it reaches the manifest URL
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "Failed to get a valid version from downloads.claude.ai (got unexpected content)." >&2
echo "This can happen if the download service is unreachable or not available in your region - see https://www.anthropic.com/supported-countries" >&2
exit 1
fi

# Download manifest and extract checksum
manifest_json=$(download_file "$DOWNLOAD_BASE_URL/$version/manifest.json")
echo "Downloaded manifest for version $version"

# Use jq if available, otherwise fall back to pure bash parsing
if [ "$HAS_JQ" = true ]; then
checksum=$(echo "$manifest_json" | jq -r ".platforms[\"$platform\"].checksum // empty")
else
checksum=$(get_checksum_from_manifest "$manifest_json" "$platform")
fi

# Validate checksum format (SHA256 = 64 hex characters)
if [ -z "$checksum" ] || [[ ! "$checksum" =~ ^[a-f0-9]{64}$ ]]; then
echo "Platform $platform not found in manifest" >&2
exit 1
fi

echo "Checksum for platform $platform: $checksum"

# Download and verify
binary_path="$DOWNLOAD_DIR/claude-$version-$platform"
echo "Downloading Claude Code binary from $DOWNLOAD_BASE_URL/$version/$platform/claude..."
if ! download_file "$DOWNLOAD_BASE_URL/$version/$platform/claude" "$binary_path"; then
echo "Download failed" >&2
rm -f "$binary_path"
exit 1
fi
echo "Downloaded binary to $binary_path"

# Pick the right checksum tool
if [ "$os" = "darwin" ]; then
actual=$(shasum -a 256 "$binary_path" | cut -d' ' -f1)
else
actual=$(sha256sum "$binary_path" | cut -d' ' -f1)
fi

if [ "$actual" != "$checksum" ]; then
echo "Checksum verification failed" >&2
rm -f "$binary_path"
exit 1
fi

chmod +x "$binary_path"

# Run claude install to set up launcher and shell integration
echo "Setting up Claude Code..."
"$binary_path" install ${TARGET:+"$TARGET"}

# Clean up downloaded file
rm -f "$binary_path"

echo ""
echo "✅ Installation complete!"
echo ""

安装命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ bash install.sh 2.1.153
Detected platform: linux-x64
Latest version: 2.1.153
#################################################################################################################################################################################################################### 100.0%
Downloaded manifest for version 2.1.153
Checksum for platform linux-x64: 214f603f31942162dac9a65f18d43b3ac646ae215240fad481c4aad6c60f2e38
Downloading Claude Code binary from https://downloads.claude.ai/claude-code-releases/2.1.153/linux-x64/claude...
#################################################################################################################################################################################################################### 100.0%
Downloaded binary to /home/wangzongwu/.claude/downloads/claude-2.1.153-linux-x64
Setting up Claude Code...

✔ Claude Code successfully installed!

Version: 2.1.153

Location: ~/.local/bin/claude


Next: Run claude --help to get started

⚠ Setup notes:
● Native installation exists but ~/.local/bin is not in your PATH. Run:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc


✅ Installation complete!
Other Articles
Article table of contents TOP
  1. 1. 问题根因
  2. 2. 解决方案(按推荐顺序)
  3. 3. 补充说明
  4. 4. claude code新的安装方式
Please enter keywords to search