报错速查:Python / TypeScript / Node.js / Rust

3 阅读21分钟

速查向。每条:报错原文 → 中文释义 → 最小复现 → 根因 → 修复 → 进阶。 AI 协作时,把报错原文 + 对应条目链接贴过去比转述高效得多。


目录


Python

1. ModuleNotFoundError: No module named 'X'

释义:sys.path 找不到这个包。

根因:四种之一

  1. 没装(pip install 漏了或装到别的解释器)。
  2. 装在了 user site,但当前用 venv。
  3. 自己写的包,但 sys.path 不含项目根(src layout 常见)。
  4. 包名和导入名不一致(pip install beautifulsoup4import bs4)。

诊断

python -c "import sys; print(sys.path)"            # path 里有没有项目根
python -c "import X; print(X.__file__)"            # 它装在哪儿
which python && python -m pip list | grep X        # 解释器 + 装了没

修复

# 解释器对不上
python -m pip install X                            # 用当前解释器装
# src layout
echo '[tool.pytest.ini_options]\npythonpath=["src"]' >> pyproject.toml
# 开发模式装自己
pip install -e .

2. ImportError: attempted relative import with no known parent package

释义:from .foo import bar 但脚本作为入口直接跑,Python 不知道它属于哪个包。

复现

python mypkg/script.py        # ❌ 直接当脚本跑,没有 parent package
python -m mypkg.script        # ✅ 作为模块跑

修复:用 -m 跑,或改成绝对导入 from mypkg.foo import bar

原理:Python 用 __package__ 解析相对导入,直接跑脚本时 __package__ 是空字符串。


3. ImportError: cannot import name 'X' from partially initialized module 'Y'

释义:循环导入,模块 Y 在被初始化的中途又被 import 了。

复现

# a.py
from b import bb
def aa(): return bb()
# b.py
from a import aa             # 💥 a 还没执行完,bb 还没定义
def bb(): return aa()

修复(按优先级)

  1. 重新设计,把公共部分抽到第三个模块。

  2. 把 import 推迟到函数内:

    def bb():
        from a import aa
        return aa()
    
  3. 改成模块级 import,函数里取属性:

    import a
    def bb(): return a.aa()
    

4. TypeError: 'NoneType' object is not subscriptable / ... is not iterable / ... has no attribute X

释义:函数返回了 None,你拿来当 list/dict/object 用。

根因:函数某条分支隐式 return None

def find(x):
    if x > 0:
        return [1, 2, 3]
    # else 隐式 return None
print(find(-1)[0])    # 💥

修复:加类型注解 + 静态检查器(mypy / pyright),编译期暴露。

def find(x: int) -> list[int]:    # 强制必须返回 list
    return [1, 2, 3] if x > 0 else []

pyright --strictmypy --strict 会拒绝隐式 None。


5. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xXX in position N

释义:按 UTF-8 读,但文件不是 UTF-8(常见 GBK/GB18030/Latin-1)。

修复

# 知道编码
open(path, encoding="gbk")
# 不知道编码 — 嗅探
import chardet
with open(path, "rb") as f:
    enc = chardet.detect(f.read(4096))["encoding"]
# 不在乎编码错误
open(path, encoding="utf-8", errors="replace")    # 替换为 U+FFFD
open(path, encoding="utf-8", errors="ignore")     # 丢弃

Windows 坑:open() 默认编码是系统 ANSI(中文 Win 是 GBK),Linux/Mac 是 UTF-8 → 同一份代码跨平台行为不同。永远显式传 encoding


6. RuntimeError: dictionary changed size during iteration

复现

for k in d:
    if d[k] is None: del d[k]    # 💥

修复

for k in list(d):                          # 快照 keys
    if d[k] is None: del d[k]

d = {k: v for k, v in d.items() if v is not None}    # 重建

set 同样有此问题(Set changed size during iteration)。


7. RecursionError: maximum recursion depth exceeded

根因:CPython 默认递归上限 1000,真的递归这么深通常说明算法该改迭代。

诊断:看 stack trace 是否真的有意义的深栈,还是无限递归。

import sys; print(sys.getrecursionlimit())
sys.setrecursionlimit(10000)         # 临时调高,但通常治标不治本

根治:改迭代 + 显式栈,或者尾递归手动展开。

def walk_iter(root):
    stack = [root]
    while stack:
        node = stack.pop()
        ...
        stack.extend(node.children)

8. RuntimeWarning: coroutine 'X' was never awaited

复现

async def f(): return 1
f()           # ❌ 创建 coroutine 对象就扔了

修复

await f()                      # 在另一个 async 里
asyncio.run(f())               # 顶层入口
asyncio.create_task(f())       # 后台跑,但记得保留引用避免被 GC

:create_task 返回的 task 必须保留引用,否则 GC 可能回收,task 静默消失。常用模式:

tasks = set()
t = asyncio.create_task(f())
tasks.add(t)
t.add_done_callback(tasks.discard)

9. asyncio.TimeoutError / TimeoutError

Python 3.11 起,asyncio.TimeoutError = 内建 TimeoutError(子类)。

try:
    async with asyncio.timeout(5):       # 3.11+,推荐
        await long_call()
except TimeoutError:
    ...

3.10 及更早用 asyncio.wait_for(coro, 5)


10. RuntimeError: Event loop is closed / ... already running

释义:在已关闭/已运行的 loop 上调度任务。

常见场景:

  • Jupyter / pytest 中已经有 loop,又调 asyncio.run()
  • 多线程,主线程关 loop,worker 还在 schedule。

修复

# Jupyter
import nest_asyncio; nest_asyncio.apply()

# 或检查再决定
try:
    loop = asyncio.get_running_loop()
    loop.create_task(f())
except RuntimeError:
    asyncio.run(f())

11. pip installerror: Microsoft Visual C++ 14.0 or greater is required

Windows 专属:某些包(lxmlpsycopg2Cython 编译)需要本地编译,缺 MSVC。

修复(任一)

  1. Build Tools for Visual Studio,选 "Desktop development with C++"。
  2. 找预编译 wheel,或换 binary 包(psycopg2-binary 替代 psycopg2)。
  3. 升级 pip,经常老 pip 找不到新的 wheel:python -m pip install -U pip

12. ssl.SSLCertVerificationError: ... certificate verify failed

释义:HTTPS 握手时,本地不信任服务器证书。

根因

  • 公司 MITM 代理(防火墙拆 TLS)。
  • 系统 CA 包过期(老镜像)。
  • macOS Python 默认不用系统 keychain,需要装 Python.org installer 自带的 Install Certificates.command

修复

# macOS
/Applications/Python\ 3.x/Install\ Certificates.command

# 公司代理:把代理 CA 加到 certifi
pip config set global.cert /path/to/corp-ca.pem
python -c "import certifi; print(certifi.where())"

# 急救(不要长期用):
import ssl; ctx = ssl._create_unverified_context()

13. pip 装包慢 / 卡死 / hash mismatch

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple X      # 国内镜像
pip install --no-cache-dir X                                   # 缓存可能坏了
pip install --index-url https://... --trusted-host ...         # HTTPS 出问题

锁版本:

pip install pip-tools
pip-compile requirements.in -o requirements.txt
pip-sync requirements.txt                                      # 严格按 lockfile

或直接上 uv:

uv pip install -r requirements.txt    # 比 pip 快 10-100x

14. TypeError: __init__() got an unexpected keyword argument 'X'

释义:你传的关键字参数,目标函数签名里没有。

最常见来源

  • 升级了库,旧参数被改名/删除。
  • pydantic v1 → v2,Config 嵌套类改 model_config
  • pandas 版本不同 API 不同。

诊断

import inspect
print(inspect.signature(SomeClass.__init__))    # 看真实签名

修复:对齐文档版本,或锁老版本继续用。


15. pydantic / dataclass 互不兼容

@dataclass
class A: x: int
class B(BaseModel): x: int

a: A = B(x=1)        # ❌ 类型上无关联

经验:整个项目挑一种用,别混。FastAPI/SQLModel 选 pydantic;无 web 框架的纯数据选 dataclass(零依赖,启动快)。


16. OSError: [Errno 24] Too many open files

根因:文件/socket 没关。

诊断

lsof -p <PID> | wc -l                      # 看具体打开数
ulimit -n                                  # 当前 soft limit

修复

# 永远用 context manager
with open(path) as f: ...
# requests session 复用,不要每次 requests.get(...)
session = requests.Session()
# httpx async
async with httpx.AsyncClient() as client: ...

调高 ulimit 只是临时方案:ulimit -n 65536


17. ImportError: DLL load failed while importing X(Windows)/ dyld: Library not loaded(Mac)

释义:Python 扩展包的原生动态库找不到/不兼容。

常见原因

  • 装了 arm64 wheel 但 Python 是 x86(M1 Mac)。
  • Visual C++ Runtime 缺(Windows)。
  • Conda 和 pip 混装同一个包,版本/链接对不上。

修复

python -c "import platform; print(platform.machine())"        # arm64 vs x86_64
# 卸载重装匹配架构的
pip uninstall X
pip install X --no-cache-dir
# Conda 用户尽量用 conda 装 native 包,别混 pip

18. decimal.InvalidOperation / float 累积误差

0.1 + 0.2 == 0.3        # False

修复

from decimal import Decimal
Decimal("0.1") + Decimal("0.2") == Decimal("0.3")   # True

# 或者比较时用 tolerance
import math
math.isclose(a, b, rel_tol=1e-9)

金额永远用 Decimal,不要用 float。


TypeScript

1. TypeError: Cannot read properties of undefined (reading 'X')

释义:访问 undefined 的属性。最高频运行时错。

修复

// 可选链 + 默认值
const name = user?.profile?.name ?? "anonymous";

// strictNullChecks 编译期暴露
// tsconfig.json: "strict": true

别用:! 非空断言糊弄运行时,它只骗 TS 不骗 JS。


2. TypeError: X is not a function

根因(按概率)

  1. 拼错了(.fitler vs .filter)。

  2. 循环依赖导致 import 拿到 undefined。

  3. 默认导出 vs 命名导出搞混:

    // bar.ts: export default function bar(){}
    import { bar } from "./bar";      // ❌ bar 是 undefined
    import bar from "./bar";          // ✅
    
  4. 用了不该用的 CJS/ESM 互操作(下方专门一节)。


3. ReferenceError: X is not defined

90% 是拼写错误或忘记 import。剩下 10%:

  • 浏览器代码引用 Node API(processBuffer__dirname)。

  • 顶层 await 在 CommonJS 文件。

  • let/const 声明前访问(TDZ):

    console.log(x);    // ReferenceError
    const x = 1;
    

4. Cannot use import statement outside a module

根因:Node 把文件当 CJS 解析,但里面是 ESM 语法。

修复(任一)

  • package.json"type": "module",所有 .js 当 ESM。
  • 文件后缀改 .mjs(ESM)或 .cjs(CJS)。
  • 构建产物里 import 不带后缀:在 tsconfig"moduleResolution": "bundler",或加 .js 后缀。

TS 特别坑:tsc 不会自动加 .js 后缀,但 Node ESM 强制要求。所以 TS 源码里要写:

import { foo } from "./bar.js";    // ✅ 是的,TS 源也写 .js

或用 "moduleResolution": "bundler"(Vite/webpack 等打包器场景)。


5. TS:Type 'X' is not assignable to type 'Y'

修复策略(按推荐顺序)

  1. 改类型反映真实数据。
  2. 类型守卫收窄:if (typeof x === "string") / if (x instanceof Date) / if ("foo" in x)
  3. discriminated union + switch (x.kind)
  4. 最后才as Yas unknown as Y 是代码异味,几乎 100% 说明类型设计有问题。
type Result = { ok: true; value: number } | { ok: false; error: string };
function handle(r: Result) {
  if (r.ok) console.log(r.value);   // 自动收窄
  else      console.error(r.error);
}

6. TS:Object is possibly 'undefined' / 'null'

const u = users.find(u => u.id === 1);
console.log(u.name);                              // ❌

if (!u) throw new Error("not found");
console.log(u.name);                              // ✅ 收窄

users.find(...)?.name;                            // ✅ 可选链

7. TS:Property 'X' does not exist on type '{}'

通常是 JSON.parse / 外部 API 返回被推断成 {}any

const u = JSON.parse(s) as User;                  // 不安全,运行时不校验

// 推荐:runtime schema 校验
import { z } from "zod";
const UserSchema = z.object({ id: z.number(), name: z.string() });
const u = UserSchema.parse(JSON.parse(s));         // 失败时 throw,字段类型有保证

库选择:zod(生态最大)、valibot(体积小)、arktype(性能/语法新)。


8. TS:Excessive stack depth comparing types / 编译变慢

复杂条件类型/递归类型导致 TS 类型检查指数爆炸。

诊断

tsc --extendedDiagnostics            # 看哪个文件慢
tsc --generateTrace ./trace          # 火焰图

修复

  • 复杂类型拆小,中间用 type Alias = ... 缓存。
  • infer 时加深度限制:T extends [infer Head, ...infer Tail] 替代递归无限层。
  • 必要时手动写类型,放弃类型推导(as Foo)。

9. TS:exports is not defined in ES module scope(打包后)

打包器把 CJS 代码塞进 ESM 文件,运行时炸。常见于:

  • 一个依赖是 CJS,但被 import 进 ESM,且 bundler 配置不当。
  • tsconfig"module" 和打包器输出对不齐。

修复:用 Vite/esbuild/Rollup 的 CJS 插件,或锁定依赖只用 ESM 版本(看 package.jsonexports)。


10. Module not found: Can't resolve 'X'(webpack/vite/esbuild)

checklist

  1. npm install 漏了。
  2. 大小写:./User vs ./user,Mac/Win 不区分但 Linux/CI 区分。
  3. tsconfig.jsonpaths 别名没在打包器同步配置(vite 需要 vite-tsconfig-paths,webpack 需要 tsconfig-paths-webpack-plugin)。
  4. monorepo 里 workspace 包没 build,引用的是 dist/ 不存在。

11. Type instantiation is excessively deep and possibly infinite

递归类型出问题。

type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> };    // OK
type Bad<T> = Bad<{ x: T }>;                                      // 💥

修复:加深度计数器

type DeepPartial<T, D extends number = 5> =
  D extends 0 ? T :
  T extends object ? { [K in keyof T]?: DeepPartial<T[K], Prev<D>> } : T;

或重新设计——一般不需要这么深。


12. 'this' implicitly has type 'any'

类方法里 this 上下文丢失,通常是 callback 没绑定:

class Foo {
  name = "x";
  log() { console.log(this.name); }
}
const f = new Foo();
setTimeout(f.log, 100);           // ❌ this 是 undefined
setTimeout(() => f.log(), 100);   // ✅ 箭头保留 this
setTimeout(f.log.bind(f), 100);   // ✅

类字段写成箭头函数也行(代价:每个实例一份函数):

class Foo { log = () => console.log(this.name); }

13. tsconfig 配错导致类型不严格

最少应该开:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true
  }
}

noUncheckedIndexedAccessarr[i]T | undefined,强烈建议开——能消除大量越界 bug。


14. 升级 TS 后大量报错

# 先看完整变更
tsc --noEmit
# 临时降版本/锁版本调试
npx typescript@5.4 --noEmit
# 暂时静音,加 issue 跟踪
// @ts-expect-error: 升级 TS 5.5 后报错,见 issue #123

@ts-expect-error 优于 @ts-ignore——错误消失时它会报错,提醒你删掉。


15. ESLint vs Prettier 冲突

npm i -D eslint-config-prettier              # 关掉 ESLint 里所有格式规则
# .eslintrc
{ "extends": ["...", "prettier"] }           # prettier 必须在最后

让 Prettier 管格式,ESLint 管 bug——分工清楚。


Node.js

1. EADDRINUSE: address already in use :::3000

释义:端口被占。

诊断 + 杀

# Linux / Mac
lsof -i :3000
kill -9 <PID>

# Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F

避免:开发环境用 nodemon / tsx watch,关进程时确保子进程也终止(process.on('SIGTERM', () => server.close()))。


2. ENOENT: no such file or directory

根因 #1:相对路径,但 cwd 不是你以为的目录。

// ❌ 依赖运行时 cwd
fs.readFileSync("./config.json");

// ✅ 相对于当前文件
import { fileURLToPath } from "node:url";
import path from "node:path";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
fs.readFileSync(path.join(__dirname, "config.json"));

根因 #2:打包后路径 dist/ 和源码 src/ 结构不同,相对路径失效 → 用 import.meta.url + Vite 的 ?raw/?url 资源导入。


3. EACCES: permission denied

文件权限不够。常见:

  • Linux/Docker 里以非 root 运行,但挂载卷的 owner 是 root。
  • npm 全局装包到 /usr/local,需 sudo。

修复

chmod +x script.js              # 可执行
chown -R $USER:$USER ./node_modules
# 别用 sudo npm install,改 prefix
npm config set prefix ~/.npm-global

4. EMFILE: too many open files

诊断

ulimit -n                                   # 当前 limit
lsof -p <PID> | wc -l                       # 实际打开

修复

ulimit -n 65536                             # 临时

代码层面:

// 限制并发
import pLimit from "p-limit";
const limit = pLimit(10);
await Promise.all(items.map(it => limit(() => processItem(it))));

// stream 必须 destroy / close
import { pipeline } from "node:stream/promises";
await pipeline(input, transform, output);   // 自动清理

5. MaxListenersExceededWarning: Possible EventEmitter memory leak

某个 EventEmitter 加了 > 10 个 listener,通常循环里反复 .on().off()

// ❌ 每次 req 加一个 listener,内存泄漏
app.on("close", () => cleanup());     // 在 handler 里

// ✅ 启动时一次
emitter.once("event", handler);        // 一次性
emitter.removeListener("event", handler);
emitter.setMaxListeners(20);           // 真的需要更多时,显式调高

别用 setMaxListeners(0)(无限),那是把警告关掉,泄漏还在。


6. UnhandledPromiseRejection → Node 15+ 默认 crash

async function main() { throw new Error("x"); }
main();                                // ❌ 没 catch,进程退出
main().catch(console.error);           // ✅

顶层兜底:

process.on("unhandledRejection", (err) => {
  logger.error("unhandled", err);
  // 决定:gracefully exit 还是继续
});
process.on("uncaughtException", (err) => {
  logger.fatal("uncaught", err);
  process.exit(1);                     // uncaught 必须退出,状态已不一致
});

7. Error: write EPIPE

向已关闭的 stream 写。最常见:管道下游(| head| grep -m1)提前退出。

process.stdout.on("error", (err) => {
  if ((err as NodeJS.ErrnoException).code === "EPIPE") process.exit(0);
});

CLI 工具必加这段,不然 mycli | head 就崩。


8. Error: connect ECONNREFUSED 127.0.0.1:5432

服务没起 / 端口错 / 防火墙挡 / Docker 网络配错。

诊断

# 服务在不在
nc -zv 127.0.0.1 5432
ss -tlnp | grep 5432             # Linux,看监听
# Docker:容器之间用服务名,不是 localhost
# docker-compose.yml: app 里连 db,host 写 "db",不是 "localhost"

9. Error: connect ETIMEDOUT

不同于 ECONNREFUSED:服务可能在但网络不通(防火墙、安全组、VPN)。

诊断

traceroute <host>
mtr <host>                        # 持续监测
curl -v --connect-timeout 5 http://host:port

代码层加超时,别让 fetch 默认无限等:

const res = await fetch(url, { signal: AbortSignal.timeout(5000) });

10. RangeError: Invalid string length / Maximum call stack size exceeded

  • 第一个:字符串拼接超过 ~512MB(V8 限制)。改用 stream。

  • 第二个:递归过深或循环引用。诊断:

    const seen = new WeakSet();
    function check(o: object) {
      if (seen.has(o)) throw new Error("cycle");
      seen.add(o);
      // ...
    }
    

JSON.stringify 遇到循环引用就抛此错。用 util.inspect(obj, { depth: 3 }) 调试。


11. JavaScript heap out of memory

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

临时

node --max-old-space-size=4096 script.js     # 默认约 1.7G,调高到 4G
NODE_OPTIONS=--max-old-space-size=4096 npm test

根治:找泄漏。

node --inspect script.js                      # Chrome devtools 接入
# 拍堆快照:devtools → Memory → Heap snapshot,对比两次找增量

常见泄漏:全局 Map/Set 只 add 不 delete、闭包持有大对象、setInterval 没 clear、Promise 链上保留过多状态。


12. npm ERR! ERESOLVE unable to resolve dependency tree

peer dependency 冲突。

解法优先级

  1. 升级老依赖到兼容新 peer 的版本。

  2. package.jsonoverrides(npm 8+)/ resolutions(yarn)/ pnpm.overrides:

    {
      "overrides": {
        "react": "18.2.0"
      }
    }
    
  3. 最后才 --legacy-peer-deps(把问题藏起来,迟早爆)。


13. Error: Cannot find module 'X'(运行时)

原因:

  • 没装(npm ci 漏了 / node_modules 删了)。
  • 在 dev 装但 prod 跑(devDependencies 里)。
  • TS 编译输出指向 dist/,但运行的是 src/(或反过来)。
  • monorepo 里 workspace 包没 build。
node --trace-warnings index.js     # 看哪儿引起的
node -e "console.log(require.resolve('X'))"   # 它能找到吗

14. (node:XX) ExperimentalWarning: ... is an experimental feature

node --no-warnings script.js                          # 关全部 warning(粗暴)
NODE_OPTIONS=--no-warnings=ExperimentalWarning npm start

更细粒度:process.on("warning", w => { if (...) return; ... })


15. tsx / ts-node ESM import 报错

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

修复:tsx 替代 ts-nodetsx 默认支持 ESM、TS、JSX,几乎零配置:

npx tsx script.ts                # 一次
npx tsx watch script.ts          # 监听
{ "scripts": { "dev": "tsx watch src/index.ts" } }

16. Error: getaddrinfo ENOTFOUND <host>

DNS 解析失败。Docker 里特别常见:容器没配置 DNS,或 host 写错(localhost vs 服务名)。

诊断

node -e "require('dns').resolve('host', console.log)"
docker exec <container> getent hosts <host>

17. npm 锁文件冲突

  • package-lock.json 在 merge 时冲突——不要手动改,以一边为基准,然后 npm install 重新生成:

    git checkout --theirs package-lock.json
    npm install
    git add package-lock.json
    
  • CI 必须 npm ci(严格按 lockfile),不要 npm install(可能改 lockfile)。


Rust

1. cannot borrow X as mutable because it is also borrowed as immutable(E0502)

let mut v = vec![1, 2, 3];
let r = &v[0];
v.push(4);              // 💥 push 可能 reallocate,r 悬空
println!("{}", r);

修复:缩短 immutable borrow 作用域,在 push 前用完 r。NLL(Non-Lexical Lifetimes)让借用作用域到最后一次使用,所以下面这个就过:

let mut v = vec![1, 2, 3];
let r = &v[0];
println!("{}", r);      // r 在这里结束生命
v.push(4);              // ✅

2. value borrowed here after move(E0382)

let s = String::from("x");
let t = s;
println!("{}", s);      // 💥 s 已被 move 给 t

修复:三选一

let t = s.clone();              // 1. 复制(代价:堆复制)
fn take(s: &str) { ... }        // 2. 改成引用,不取所有权
take(&s);
use std::rc::Rc;
let s = Rc::new(String::from("x"));    // 3. Rc 共享所有权
let t = Rc::clone(&s);

线程间共享用 Arc(原子计数,跨线程安全)。


3. cannot move out of borrowed content / cannot move out of index of Vec(E0507)

fn f(v: &Vec<String>) -> String {
    v[0]               // 💥 不能 move 出借用的内容
}

修复

v[0].clone()                              // 复制一份
v.first().cloned().unwrap_or_default()    // 优雅版
&v[0]                                     // 返回引用,改签名 -> &String
std::mem::take(&mut v[0])                 // 取走,留空默认值(需要 &mut)

4. cannot return reference to local variable(E0515)

fn f() -> &str {
    let s = String::from("x");
    &s                  // 💥 s 离开作用域被 drop
}

修复

fn f() -> String { String::from("x") }                  // 返回所有权
fn f<'a>(input: &'a str) -> &'a str { &input[..1] }     // 返回入参的子引用

5. the trait bound 'X: Y' is not satisfied(E0277)

修复路径(按推荐)

  1. #[derive(...)](标准 trait):

    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    struct Id(u64);
    
  2. 手动 impl:

    impl Display for MyType {
        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "...") }
    }
    
  3. 加 trait bound 到泛型签名:fn foo<T: Display>(x: T)

  4. newtype 绕开 orphan rule:struct Wrap(ExternalType); impl SomeTrait for Wrap { ... }


6. mismatched types / expected X, found Y(E0308)

最常见子情况:

  • &str vs String:fn(&str)String 需要 &s(deref coercion 通常自动,但泛型不行)。
  • Vec<T> vs &[T]:fn(&[T])Vec<T> 需要 &v
  • i32 vs usize:索引必须 usize,显式 as usize(注意溢出)或用 try_into()?
  • Result<T, E1> vs Result<T, E2>:用 ?From<E2> for E1 没实现 → thiserror / anyhow 简化。

7. cannot find macro 'X' in this scope

宏需要 use#[macro_use],或者 crate 没暴露宏。

use serde::{Serialize, Deserialize};       // proc macro,正常 use
use log::info;                              // declarative macro,2018+ 也用 use

8. expected struct 'X', found struct 'X'(同名不同 crate)

依赖图中同一 crate 出现两个版本,类型不互通。

cargo tree -d                  # 找重复

修复

# Cargo.toml
[patch.crates-io]
tokio = { version = "1" }      # 强制所有 tokio 走这个版本

或显式升级依赖到兼容版本。


9. future cannot be sent between threads safely

async fn f() {
    let rc = Rc::new(1);       // Rc 非 Send
    tokio::spawn(async move {
        println!("{}", rc);    // 💥 task 跨线程,捕获了非 Send
    });
}

修复

let arc = Arc::new(1);                 // Arc 是 Send
tokio::spawn(async move { println!("{}", arc); });

std Mutex 跨 await 的坑:std::sync::Mutex 持有 guard 跨 .await 会死锁(同任务再请求自己持有的锁,但 runtime 可能调度走);async 场景用 tokio::sync::Mutex,或缩短持锁范围到不跨 await:

let value = {
    let g = mutex.lock().unwrap();
    g.compute()                        // 同步代码,scope 结束前 drop guard
};                                     // <- guard 在这里 drop
do_async(value).await;                 // 然后再 await

10. cannot infer type / type annotations needed(E0282/E0283)

let v = Vec::new();         // 💥 不知道 Vec<什么>
let v: Vec<i32> = Vec::new();
let v = Vec::<i32>::new();
let v = vec![1, 2, 3];      // 从字面量推

let x = "1".parse()?;       // 💥 parse 成什么?
let x: i32 = "1".parse()?;
let x = "1".parse::<i32>()?;

11. borrow of moved value 在闭包里

let s = String::from("x");
let f = move || println!("{}", s);
f();
println!("{}", s);          // 💥 s 已 move 进闭包

修复:let f = move || println!("{}", s.clone()); 或闭包前 clone 一份。

Fn/FnMut/FnOnce 的选择:闭包默认按需,move 强制取所有权(用于 spawn / 跨线程)。


12. lifetime 错误总集(E0106, E0621, ...)

最常见:struct 持有引用没标 lifetime:

struct S { name: &str }                      // ❌
struct S<'a> { name: &'a str }               // ✅

返回引用没标:

fn longest(a: &str, b: &str) -> &str         // ❌ 哪个的 lifetime?
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str    // ✅

心法:lifetime 是给编译器证明"我这个引用不会比来源活得久"的标注,不影响运行时。


13. unresolved import 'crate::X' / could not find 'X' in the crate root

模块没声明:

// src/lib.rs 或 src/main.rs
mod foo;        // 声明 src/foo.rs 或 src/foo/mod.rs
mod bar;
pub use foo::Bar;

子目录:

src/
  lib.rs        # mod net;
  net/
    mod.rs      # pub mod tcp; pub mod udp;
    tcp.rs
    udp.rs

2018+ 也支持:

src/
  lib.rs        # mod net;
  net.rs        # pub mod tcp; pub mod udp;
  net/
    tcp.rs
    udp.rs

14. index out of bounds: the len is N but the index is M(运行时 panic)

数组越界。Rust 不像 C 那样 UB,直接 panic,但仍是 bug。

避免

v[i]                        // panic
v.get(i)                    // Option<&T>,没就 None
v.get(i).copied().unwrap_or(0)

15. attempt to add with overflow(debug)/ 静默 wrap(release)

debug:溢出 panic;release:溢出 wrap(默认),不报错——这是真 bug 源

let x: u8 = 200;
let y: u8 = 100;
let z = x + y;             // debug panic,release 变 44

// 显式选择行为
x.checked_add(y)           // Option<u8>
x.wrapping_add(y)          // 显式 wrap
x.saturating_add(y)        // 饱和(到 u8::MAX)
x.overflowing_add(y)       // (result, bool)

或在 Cargo.toml release 也开 overflow check:

[profile.release]
overflow-checks = true

16. error[E0599]: no method named 'X' found for type 'Y'

原因

  • 方法在某个 trait 上,use 这个 trait:

    use std::io::Read;          // 不 use 这个,Read trait 上的 read() 用不了
    
  • 类型实际不一样(&str vs StringVec vs &[T])。

  • macro 展开后类型变了。

诊断:cargo doc --open 直接看类型的所有方法。


17. proc-macro derive 'X' not found in scope

use serde::Serialize;                    // 必须 use trait
#[derive(Serialize)]                     // 然后 derive
struct S;

#[derive(serde::Serialize)]              // 全路径,免 use
struct S;

Cargo.toml 必须开启对应 feature:

serde = { version = "1", features = ["derive"] }

18. linker error / cannot find -lXXX

链接外部 C 库失败。

诊断

cargo build -vv     # 看完整 link 命令
pkg-config --libs xxx

修复

# Ubuntu
sudo apt install libxxx-dev pkg-config
# Mac
brew install xxx
# Windows:vcpkg / 装好的 lib 加到 PATH/LIB

# build.rs 里指引 linker
println!("cargo:rustc-link-search=/path/to/lib");
println!("cargo:rustc-link-lib=xxx");

通用 Build / Dependency 报错

1. "本机能跑,CI 挂"

按出现频率 checklist:

  1. lockfile 没提交(package-lock.json / poetry.lock / Cargo.lock / uv.lock)。
  2. 环境变量:本地 .env,CI 没设。
  3. 大小写:User.ts import 成 ./user,Mac/Win 过,Linux 挂。
  4. 行尾:CRLF/LF 混,bash\rcommand not found
    修复:.gitattributes* text=auto eol=lf,git add --renormalize .
  5. 时区:CI 是 UTC,本地不是。本地 TZ=UTC pytest 试一遍。
  6. locale:LANG=C 跑一遍排查。
  7. 并行度:pytest -n0 / 单线程跑一遍。
  8. 资源:CI 容器 2C4G,本地宽松,超时被压爆。
  9. 依赖跨平台二进制:sharpnode-gyppyarrowtensorflow 需对应平台 wheel。
    修复:pip install --only-binary=:all: 强制 wheel,或在 CI 上装编译工具链。
  10. shell 差异:本地 zsh/fish,CI bash;set -eo pipefail 行为不同。

2. 循环依赖

  • Python:ImportError: cannot import name 'X' from partially initialized module
  • TS/Node:运行时 import 成 undefined,常表现为 is not a function
  • Rust:crate 间编译期拒绝;模块内循环依赖通过 trait 抽象解耦

通用修复:抽出公共部分到第三个模块;或依赖倒置(高层定义 trait,低层实现)。


3. Dependency hell

Conflicting peer dependency: react@17 vs react@18

解法优先级

  1. 升级老依赖。
  2. overrides / resolutions / [patch.crates-io] 强制锁版本。
  3. 最后才 --legacy-peer-deps / --force(把问题藏起来,迟早炸)。

预防

  • 每个项目锁住主要依赖的 major 版本。
  • 用 Renovate / Dependabot 持续小步升级,而不是几年一次大跳。

4. Docker 里能跑,Compose 里挂

最常见:服务名 vs localhost

services:
  app:
    environment:
      DB_HOST: db        # ✅ 用服务名
      # DB_HOST: localhost  # ❌ localhost 是 app 容器自身
  db:
    image: postgres

服务启动顺序:depends_on 只保证启动顺序,不保证就绪。健康检查:

  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 2s
      retries: 30
  app:
    depends_on:
      db:
        condition: service_healthy

5. Apple Silicon 跨架构问题

rosetta 装的二进制是 x86_64,native 是 arm64,混用挂。

arch                              # 当前 shell 架构
uname -m                          # 系统架构
file $(which python)              # 二进制是什么架构

经验

  • 单一架构用到底,不要 native + rosetta 混。
  • Docker 在 M 系列上:docker run --platform linux/amd64 ... 跑 x86 镜像(慢但能跑)。

如何贴报错给 AI

标准模板

我遇到这个报错:

<报错完整原文,包括 stack trace,不要省略也不要转述>

环境:
- 语言/版本:Python 3.11 / Node 20.10 / Rust 1.78 / TS 5.4
- 框架:FastAPI 0.110 / Next.js 14.2 / tokio 1.36 / Vite 5
- OS:Linux x86_64 / macOS arm64 / Windows 11
- 复现步骤:1. ... 2. ... 3. ...

我已经试过的:
- [尝试 1] → 结果
- [尝试 2] → 结果

相关代码(最小复现,< 30 行):
<贴>

请:
1. 一句话说明这个报错的根本含义。
2. 按概率列 3 个可能原因。
3. 每个原因给出验证命令/检查项,不要直接改我代码。
4. 等我反馈再给修复方案。

为什么这样写有效

  • 报错原文 → AI 不必猜。
  • 环境 → 排除版本差异(同一报错,Python 3.9 vs 3.12 修法可能不同)。
  • 已试过的 → 避免无用建议反复出现。
  • 要求先诊断后修复 → 避免 AI 看一眼就乱改。

反模式

"我代码报错了,帮我看看"           → 没有信息
❌ "怎么修这个 undefined 错误"        → 一万种可能
❌ "直接帮我改代码"                   → AI 容易幻觉
❌ "刚才那个还是不行"                 → 还是不贴新报错
❌ 截图报错(图片识别会丢字符)        → 用文本

一个 prompt 技巧:让 AI 先用人话复述

读完上面,先用 100 字以内告诉我:
1. 你理解的我现在的处境是什么?
2. 你打算怎么诊断?
等我确认你理解对了,再开始。

防止 AI 跑偏到错的方向上忙活半天。