# 常见错误与排查

## 排查顺序

模块装上了但没效果，按这个顺序查：

1. 模块在列表里**开着**吗?客户端不在「直连」或「全局」模式吗?这两个模式下所有模块规则整体失效。
2. 规则命中了吗?—— 换成 `REJECT` 试一次。如果目标彻底连不上，说明规则命中了，问题在出口；如果照常能连，说明规则没命中。
3. 匹配值有没有写成大写?域名类的值必须自己写小写，大写永远不命中。
4. 有没有把注释写在规则行尾?行尾注释会被并进出口名。
5. 出口名在 `[Proxy Group]` 里定义过吗?未定义且不是客户端已有出口名时，规则会使用「默认」出口，且不会显示错误。
6. 用到 `GEOIP` / `GEOSITE` 的，名字拼对了吗?模块详情页里那个规则集下载到多少条?**0 条 = 永远不命中**。
7. 用到改写或脚本的：解密开关开了吗?根证书装了并且**完全信任**了吗?目标域名写进 `[MITM] hostname` 了吗？
8. 还是不行，看日志。

## 没有错误提示但未生效

这是最常见的一类。原因几乎总在下面这张表里。

| 现象 | 原因 |
|---|---|
| 匹配值写了大写 | 只有被匹配的域名被转小写，规则里的值原样使用。`DOMAIN-SUFFIX,Google.COM` 永不命中 |
| 规则行尾写了 `# 注释` | 没有行尾注释，`DIRECT # 注释` 整个被当成出口名，落到「默认」 |
| 规则已配置，流量仍使用原出口 | 出口名未定义，因此使用了「默认」出口 |
| 规则针对私网 IP / BT / ping | 客户端有前置规则把它们判给直连，排在所有模块规则之前 |
| 客户端在「直连」或「全局」模式 | 这两个模式下模块规则整体不参与 |
| `GEOSITE,xxx` 从不命中 | 名字在规则集目录里不存在，下载 404，规则空转 |
| `GEOSITE` / `GEOIP` 刚导入时不命中 | 规则集还没下载完，等一会或在模块详情页手动重拉 |
| 前面存在更宽泛的规则 | 规则从上到下匹配，第一条命中后停止。`GEOSITE,cn,DIRECT` 写在特定境外服务规则之前时，后者可能没有机会匹配 |
| 改写/脚本一点动静没有 | 域名没写进 `[MITM] hostname`；或者根证书没「完全信任」；或者你在 Android 上 |
| `[MITM] hostname` 只剩排除项 | 一条包含规则都没有时整个解密层不启用 |
| YouTube / Google 系的改写不生效 | 走了 HTTP/3，没经过解密层。加一条 UDP 阻断规则 |
| 脚本启用后没有效果 | 脚本可能抛出异常。发生异常时请求保持原样继续处理，客户端不显示脚本错误 |
| `[Body Rewrite]` / `[Map Local]` 里的双引号消失 | 这些配置段解析时会移除双引号，且不支持 `\"`。正则中使用 `\x22`，正文使用 `data-type=base64` |
| `[URL Rewrite]` 整行没生效 | 行尾动作拼错了，比如 `reject-img-drop`、`reject-200-no-drop` 这些不存在的组合 |
| `DST-PORT,80-443` 不生效 | 不支持端口区间，只能写单个端口 |
| `URL-REGEX` / `USER-AGENT` 规则不生效 | 这些类型不受支持，配置会被忽略。按路径拦截应使用 `[URL Rewrite]` |
| 新建的分组未显示 | 分组名与已有出口重名，新分组被忽略 |
| 分组只剩一个成员 | 手写的成员名都没定义过，合并成同一个「默认」出口了 |

## 内核无法启动或节点列表为空

配置被拒绝了，三个原因：

1. **分组正则用了 RE2 不支持的语法** —— `policy-regex-filter` / `exclude-regex` 里写了环视 `(?=` `(?!` `(?<=` `(?<!` 或反向引用 `\1`。这是最常见的一个。
2. **分组是空的** —— 既没写成员也没写正则筛选(`我的组 = select`)，或者写的成员全被丢掉(`广告 = select, REJECT`)。
3. **规则里的值非法** —— `IP-CIDR` 的值不是合法 IP 或网段，`DOMAIN-REGEX` 的正则编译不过。

解决：关掉刚装的模块，如果恢复了就是它；逐条对照上面三点改。

> **分组重名不会阻止内核启动。** 重名时新分组会被忽略，内核仍可正常运行；此时表现为新分组未显示，而不是节点列表为空。重复安装同一模块时也是如此。

## 写法陷阱

### 注释只能独占一行

```ini
# 对
DOMAIN-SUFFIX,a.com,DIRECT

# 错:出口变成了 "DIRECT # 走直连",落到「默认」
DOMAIN-SUFFIX,a.com,DIRECT # 走直连
```

### 匹配值要写小写

```ini
# 错,永不命中
DOMAIN-SUFFIX,Google.COM,默认

# 对
DOMAIN-SUFFIX,google.com,默认
```

`GEOIP` / `GEOSITE` 的名字例外，大小写都行。

### 逗号

`[Proxy Group]` 的定义按逗号切分。正则里带 `{2,3}` 这类量词时**整个值要用双引号包起来**:

```ini
测试 = url-test, policy-regex-filter="(?i)节点[0-9]{2,3}", interval=300
```

`[Script]` 的 KV 列表也按逗号切，但不含 `=` 的片段会自动并回上一段，所以 `pattern` 里的量词、`argument` 里的 JSON 一般不会被切断。但 `argument` 的值里**出现 `=` 就会被当成新的 key**，那一串从此断掉。

### 双引号会在解析时被移除

`[URL Rewrite]` / `[Header Rewrite]` / `[Body Rewrite]` / `[Map Local]` 四个配置段按空白分隔字段，解析时会移除所有双引号，且不支持 `\"` 转义：

- 正则或替换串里要一个字面双引号，写 `\x22`。
- 要输出一段 JSON，用 `[Map Local]` 的 `data-type=base64`，或者用 `[Body Rewrite]` 的 jq 变体。
- 值里要有空格，把整段用双引号包住(引号本身会被剥掉，起的是「不切分」的作用)。

### 正则用的是 RE2

分组筛选、规则里的 `DOMAIN-REGEX`、改写和脚本的 `pattern`，全部是 RE2:

- 没有环视：`(?=)` `(?!)` `(?<=)` `(?<!)`
- 没有反向引用：`\1` `\2`
- `(?i)` 可以用，写在开头

从其他客户端移植正则时需要检查这两项。JavaScript 支持这些语法，但此处不支持；用于分组筛选时会导致内核无法启动。

### `*.example.com` 不含 `example.com`

`[MITM] hostname` 里的 `*.example.com` 只匹配子域。主域要单独写一条：

```ini
hostname = example.com, *.example.com
```

`DOMAIN-SUFFIX,example.com` 则是两个都匹配，不用重复写。

### `[MITM]` 里的排除优先

只要命中任何一条 `-` 排除，就一定不解密，不管别的规则怎么写。全是排除项时整个解密层不启用。

### `FINAL` 会替换全局默认规则

`FINAL` 指定其他规则均未命中时使用的出口，并替换客户端原有的默认规则。仅修改少量域名出口时**不要配置 `FINAL`**。配置多条时最后一条生效；`FINAL,REJECT` 会被忽略。

### 模块不能定义节点

`[Proxy]` 段会被忽略。节点由客户端管理，模块只能通过 `[Proxy Group]` 的正则筛选引用节点。`[General]` 仅支持 `dns-server`，其他全局设置不受模块控制。

### DNS 配置没生效

- **地址写成域名**:`server:dns.corp.local` 整条被丢掉，只收 IP(可带端口和 `tls://` `https://` 前缀)或 `system`。
- **域名模式写成裸通配**:单独一个 `*` 或 `+.` 不接受，得写到具体域名(`+.corp.com`)。
- **目标是修改节点或入口域名的解析**:模块 DNS 配置只作用于用户访问的目标域名；节点和入口域名固定使用客户端内置的解析路径。
- **解析出内网地址但连不上**:再补一条 `DOMAIN-SUFFIX,内网域名,DIRECT`，否则地址可能被路由进代理。
- **只写了 `[Rule]` 想把内置判直连的域名改走节点**:改不动。那条规则确实生效了，但 DNS
  可能已经获得中国大陆的真实 IP，随后流量仍会经代理连接该地址。应同时配置
  `[Host] 域名 = server:fakeip`，分配虚拟 IP 并由 `[Rule]` 决定出口。

### 一行一个值

```ini
# 错:b.com 被解析为出口名,规则将使用「默认」出口且不显示错误
DOMAIN-SUFFIX,a.com,b.com,默认

# 对
DOMAIN-SUFFIX,a.com,默认
DOMAIN-SUFFIX,b.com,默认
```

## 关于解密

- **Android 端不支持**，`[MITM]` 及其后面几段永远不生效。
- 做了证书钉扎的 App 连不上，没有绕过办法。这不是配置写错了。
- 不要写 `hostname = *`。全量解密会让设备明显变慢，还会让一批 App 直接连不上。
- 证书装完之后，iOS 上还要去「设置 → 通用 → 关于本机 → 证书信任设置」里勾上。少这一步全部改写都不生效，而且没有任何提示。

## 导入时的提示

- 规则集名字核对失败：`GEOIP` / `GEOSITE` 的名字在目录里不存在，改掉。
- 提示「无法核对」:一般是网络不通，规则集本身可能是对的，连上网再看。

除此之外没有其他导入提示。不支持的规则类型、无效改写行和被忽略的重名分组不会显示错误。导入成功仅表示文件可读取，不表示每一行配置都已生效。
