1 分钟速览 — YAML 写法要点
- 缩进只用空格,禁止使用 Tab。2 个空格是事实标准。
key: value中冒号后面必须有空格。key:value会被当作一个字符串。- 列表用
-(短横线加空格),映射用key: value。 - 可能被误判为数字、布尔值、日期的值要加引号:
version: "1.0"。 - 想快速检查错误,把内容粘贴到 FormatArc YAML to JSON 转换工具,带行号的错误信息会直接定位问题位置。
YAML 是什么,在哪里会用到
YAML(YAML Ain't Markup Language)是一种人类易读的文本结构化数据格式。它处理的数据模型和 JSON 相同——字符串、数字、布尔值、null、列表、映射——但语法上不用花括号,而是用缩进来表达层级结构。
如果你在做 DevOps 或云原生开发,大概率已经天天和 YAML 打交道:
- Kubernetes 清单文件、Helm Chart
- Docker Compose 配置文件
- GitHub Actions、GitLab CI、CircleCI 工作流
- Ansible Playbook
- OpenAPI 规范
- 静态网站生成器(Hugo、Jekyll、Eleventy)
静态网站生成器的 frontmatter 也常用 YAML 编写,转成 JSON 的完整流程见 Markdown frontmatter 是什么。
这篇文章会带你过一遍 YAML 语法中实际会遇到的所有部分,配有具体示例和新手最常踩的坑。刚接触 YAML、想先看概览的话,可以从 YAML 是什么 读起;想直接对比 YAML 和 JSON,可以看 YAML 和 JSON 的区别;想了解转换步骤,参考 YAML 转 JSON 指南。
YAML 的三种基本构件
YAML 文件里出现的所有数据,都是以下三种之一:
- 标量(Scalar)—— 字符串、数字、布尔值、null 等单个值
- 序列(Sequence)—— 有序列表
- 映射(Mapping)—— 键值对(即对象或字典)
这三种可以自由嵌套。映射里可以放列表,列表里可以放映射。光靠它们就能表达所有 JSON 兼容的结构。
缩进规则
YAML 用缩进来表达层级结构。必须记住的规则:
- 只用空格,不能用 Tab 字符。Tab 在大多数解析器中会直接报语法错误。
- 确定缩进宽度后,整个文件保持一致(通常用 2 个空格)。
- 同一层级的元素缩进深度必须相同。
- 没有闭合符号,结构完全由缩进决定。
正确的写法示例:
database:
host: localhost
port: 5432
credentials:
user: admin
password: secret
database 是一个映射,包含 host、port、credentials。credentials 又是一个嵌套映射。2 个空格的缩进让你一眼看清整个结构。
键值对(映射)的写法
映射的格式是 key: value,冒号后面必须有一个半角空格。如果写成 key:value 不带空格,它会被当作一个普通字符串,而不是映射。
name: Alice
age: 30
is_admin: true
bio: null
键通常是简单字符串,但加引号后可以包含空格。
"full name": Alice Cooper
值的类型可以是标量、序列、映射——YAML 支持的所有数据类型都行。
列表(序列)的写法
序列在每行开头写 - (短横线加一个半角空格)。
fruits:
- apple
- banana
- cherry
列表里可以嵌套映射。
users:
- name: Alice
role: admin
- name: Bob
role: editor
每个短横线标志一个新列表项的开始,到下一个短横线出现之前的内容都属于该项。
块样式与流样式
前面展示的全是块样式(Block style):一行一个条目,用缩进表示嵌套。YAML 也支持类似 JSON 的内联流样式(Flow style)。
fruits: [apple, banana, cherry]
users: [{name: Alice, role: admin}, {name: Bob, role: editor}]
流样式在写短列表时很方便,但数据一多可读性就急剧下降。实际文件中建议默认用块样式。流样式中忘了闭合 [ 会导致不同解析器报不同错误(详见后文解析器错误对照表)。
字符串与引号:什么时候必须加
YAML 中大多数字符串可以不加引号直接写。
greeting: Hello, world
以下情况必须加引号:
- 值可能被误判为其他类型:
version: "1.0"、country: "NO"、postal_code: "07030" - 值以 YAML 结构字符开头:
[、]、{、}、,、*、|、>、%、@、`、"、'、#、&、!。开头的-、:、?只在后面紧跟空格时才有问题 - 值中包含冒号加空格(
:),会被误判为映射 - 想使用
\n或\t等转义序列
单引号(')和双引号(")都可以用。双引号会解析转义序列,单引号则原样保留字面值。
escaped: "line1\nline2"
literal: 'line1\nline2'
实际会造成问题的字符分成两组,组别决定了是否需要引号。下表是本站转换工具使用的解析器(yaml (eemeli) 2.8.3,YAML.parse 默认配置)的行为(2026-08-15 实测,复现脚本在仓库 scripts/benchmarks/yaml-quote-requirements/ 中)。中间列写"安全"的话,只要该字符不在值的最前面,就可以不加引号。
| 字符 | 放在值最前面时 | 放在值中间时 | 单引号是否够用 | 双引号 |
|---|---|---|---|---|
[ ] { } , | 解析错误 | 安全 | 够用 | 可用 |
* | 解析错误(被当作别名) | 安全 | 够用 | 可用 |
& | 不报错,被当作锚点,值丢失 | 安全 | 够用 | 可用 |
! | 不报错,被当作标签 | 安全 | 够用 | 可用 |
# | 不报错,整个值被当作注释变成 null | 前面没空格就安全 | 够用 | 可用 |
| > | 解析错误(被当作块标量) | 安全 | 够用 | 可用 |
% @ ` | 解析错误(保留字符) | 安全 | 够用 | 可用 |
- ? | 单独安全,后面接空格则报错 | 安全 | 够用 | 可用 |
: | 单独安全,后面接空格则报错 | 后面接空格则无论位置都报错 | 够用 | 可用 |
" | 解析错误 | 安全 | 够用 | 需要 \" 转义 |
' | 解析错误 | 安全 | 不够,需写成 '' | 推荐用这个 |
从这张表可以得出两个结论。第一,值中间真正危险的只有 : 和 #,所以 url: http://example.com/a,b 不加引号也完全安全。其余都是"开头字符"问题。第二,单引号除了引号字符本身以外几乎能安全包裹所有情况。这就是为什么粘贴 Windows 路径或正则表达式时单引号更安全。只有当你需要 \n 或 \t 被解析为真正的换行或制表符时,才用双引号。
模板语法 {{ }} 写在值开头会炸
Helm 模板或 Ansible 变量展开如果没有渲染就直接丢给 YAML 解析器,开头的 { 会触发特殊字符陷阱。
# 未渲染的 Helm 模板
image: {{ .Values.image }}
{{ 会被解析为两层嵌套的流映射。而且不同解析器的失败方式不同。实测(2026-07-12,复现脚本在仓库 scripts/benchmarks/yaml-syntax-errors/ 中)表明 PyYAML 和 ruamel.yaml 会报 found unhashable key 错误,但 js-yaml 和 eemeli/yaml 完全不报错,悄悄返回 {"image": {"[object Object]": null}} 这样的损坏对象。不报错意味着问题要到了流水线后段才会暴露,这才是最棘手的部分。
解决办法有两个:把整个值加引号让它变成字符串(image: "{{ .Values.image }}"),或者只在模板渲染完成之后才校验 YAML。另外 GitHub Actions 的 ${{ }} 以 $ 开头,不会被解析为流映射,不存在这个问题。
多行字符串
长文本块有两种写法。
字面量块 | 保留源代码中的换行原样。
description: |
这是第一行。
这是第二行。
空行后的第四行。
折叠标量(Folded scalar)> 把换行折叠为空格,适合在源码中折行书写长段落。
paragraph: >
这段长文字在源码中
分成了多行书写,
YAML 会把它合并为一行。
Chomp 指示符:strip / clip / keep
YAML 的块标量有一个 chomp 指示符,决定尾部换行如何处理。指示符紧跟在 | 或 > 后面。
| 指示符 | 行为 | 示例 |
|---|---|---|
| (无)— clip | 保留最后一个换行。默认行为。 | | |
- — strip | 去掉所有尾部换行。 | |- >- |
+ — keep | 保留所有尾部空行。 | |+ >+ |
clip: |
line one
line two
strip: |-
line one
line two
keep: |+
line one
line two
折叠形式(>、>-、>+)同样适用这三种模式。|- 适合把 YAML 嵌入 JSON 或环境变量时不想有尾部换行的场景。|+ 适合生成 Shell 脚本时尾部空行有意义的情况。
类型与解析器类型推断
YAML 会对不加引号的值做自动类型推断。同一个字面量,根据解析器实现的 YAML 版本和使用的 schema,可能被解析为整数、浮点数、日期或字符串。
integer: 42
hex: 0xFF # 255(整数,十六进制)
octal: 0o17 # 15(整数,八进制,YAML 1.2)
octal_legacy: 0644 # 420(整数,八进制,YAML 1.1)— 文件权限陷阱
float: 3.14
negative: -7
exponential: 1e3 # 1000.0(浮点数,指数表示)
infinity: .inf # +Infinity(浮点数)
negative_infinity: -.inf
not_a_number: .nan # NaN(浮点数)
boolean_true: true
boolean_false: false
null_value: null
tilde_null: ~
date: 2026-04-13
timestamp: 2026-04-13T09:30:00Z
这些值加引号后都可以固定为字符串。
version_string: "1.0" # 不是数字 1.0
zip_code: "07030" # 不是数字 7030
file_mode: "0644" # 不是八进制整数
下表汇总了不加引号的字面量在现代 YAML 1.2 Core schema 加载器(PyYAML、js-yaml、SnakeYAML 默认)和 YAML 1.1 加载器(旧版 PyYAML、Symfony YAML)中分别变成什么。大多数意外行为就藏在这两列的差距里。
| 字面量 | YAML 1.2 Core | YAML 1.1 | 注意事项 |
|---|---|---|---|
42 | integer (42) | integer (42) | — |
0xFF | integer (255) | integer (255) | 十六进制解析是规格定义的行为 |
0o17 | integer (15) | (不识别) | 仅 YAML 1.2 |
0644 | integer (644) | integer (420, 八进制) | 文件权限解析因版本而异 |
1e3 | float (1000.0) | float (1000.0) | 部分工具显示时会去掉 .0 |
.inf / -.inf | float (±Infinity) | float (±Infinity) | 无法序列化为 JSON |
.nan | float (NaN) | float (NaN) | 无法序列化为 JSON |
2026-04-13 | string | date(日期对象) | JSON 与 YAML 往返转换时类型会变 |
2026-04-13T09:30Z | string | timestamp | 同上 |
true / false | boolean | boolean | — |
yes / no / on / off | string | boolean | "Norway problem" |
NO | string | boolean (false) | 下节详述 |
~ / null / Null / NULL | null | null | 大小写均为 null |
1.0 | float (1.0) | float (1.0) | 部分工具会重新序列化为 1 |
如果你的解析器接近生产环境,最右边一列的所有项都应视为潜在 bug。最快的确认方式是拿一个有代表性的文件粘贴到 FormatArc 的 YAML to JSON 转换工具,看 JSON 输出:"NO" 还是 false,"2026-04-13" 还是 ISO 日期字符串,一目了然。
两列产生差异的原因是 YAML 1.1 和 YAML 1.2 对类型推断的定义不同。YAML 1.1 包含了一组宽泛的隐式类型标签——包括时间戳、六十进制数、以及引发 Norway problem 的大量布尔词汇。YAML 1.2 用更严格的 Core schema在新标签页中打开 替代了它。Core schema 将布尔值限定为 true 和 false(规格中的 Core 正则表达式也接受首字母大写或全大写的 True/TRUE/False/FALSE,但不再接受 yes/no/on/off),废除了隐式时间戳和六十进制标签,其余部分直接跟随 JSON 的值类型。完整的正则表达式规则集见 YAML 1.2.2 规格在新标签页中打开。当两个工具对不加引号的值产生分歧时,原因几乎总是一个实现了 1.1 规则,另一个实现了 1.2 Core schema。
Norway problem — NO 变成 false 的陷阱
YAML 中最著名的陷阱就是"Norway problem"。YAML 1.1 解析器(PyYAML、Symfony YAML、旧版 SnakeYAML 等,目前仍广泛使用)会把不加引号的 NO 解析为布尔值 false。如果你这样写国家代码列表:
countries:
- DE
- FR
- NO
- SE
解析的瞬间就变成了 ["DE", "FR", false, "SE"]。YES、ON、OFF、Y、N 以及各种大小写变体,根据解析器不同都会触发同样的问题。
解决办法是把可能被误判的值加引号。
countries:
- "DE"
- "FR"
- "NO"
- "SE"
YAML 1.2 虽然把布尔值限定为 true / false,但大量生产工具仍内置 1.1 的加载器。国家代码、语言代码、版本字符串、短标识符,全部加引号才安全。
严格的新版布尔集合定义在 YAML 1.2.2 规格在新标签页中打开 中,旧版工具仍在实现的规则见 YAML 1.1 规格在新标签页中打开。
注释
注释从 # 开始到行尾结束。可以独占一行,也可以写在值后面。
# 上游请求的最大重试次数
retries: 3 # 再高就会超过上游超时
注释是 YAML 相比 JSON 在配置文件场景下最大的优势之一。用它来说明"为什么设这个值",而不是"这是什么"。转成 JSON 后所有注释都会消失,所以 YAML 文件本身才是可信源。如果非要在 JSON 里写注释,JSON 可以注释吗 介绍了 JSONC / JSON5 等 4 种替代方案。
锚点与别名:复用定义
YAML 用 & 定义锚点(Anchor),用 * 引用别名(Alias)。<<: 合并键(Merge key)可以把一个映射作为默认值引入。
defaults: &defaults
adapter: postgres
host: db.internal
pool: 5
development:
<<: *defaults
database: myapp_dev
production:
<<: *defaults
database: myapp_prod
pool: 20
production 继承了 defaults 的配置,只覆盖了 pool 的值。这是在不复制粘贴的情况下共享环境配置的干净写法。
合并键(<<:)共享配置
<<: 合并键是锚点最实用的搭档。它把一个映射的键引入另一个映射,让你可以表达"和那个一样,只是这里改一下",不用反复复制。Docker Compose、GitLab CI、Rails 的 database.yml 中都大量使用这种模式。
base: &base
image: node:20
restart: unless-stopped
environment:
NODE_ENV: production
services:
api:
<<: *base
command: npm run start:api
worker:
<<: *base
command: npm run start:worker
environment:
NODE_ENV: production
WORKER_QUEUE: high
使用时有两个注意点:
- 合并键只做一层(浅合并)。嵌套映射(如上例中的
environment)不会被深度合并,而是整体替换。 - 合并键是 YAML 1.1 的特性。严格的 YAML 1.2 解析器可能忽略它,但 Docker Compose 和 GitLab 仍然支持 1.1 语义,所以正常使用没问题。
schema 与标签:YAML 如何决定类型
YAML 1.2 定义了三种控制不加引号的字面量如何解释的 schema。
- FailSafe — 只支持字符串、映射、序列。最安全的 schema,其他一切字面量都变成字符串。很少作为默认。
- JSON — 支持 JSON 兼容类型(字符串、整数、浮点数、布尔值、null、映射、序列),与
JSON.parse的结果一致。 - Core — 通常的默认值。在上面表格的类型推断规则基础上增加了十六进制、八进制、
.inf、.nan、~的支持。
大多数解析器默认使用 Core(PyYAML 的 safe_load、js-yaml 的默认值、SnakeYAML 的 SafeConstructor)。Symfony YAML 仍然默认使用 YAML 1.1 语义。JSON schema 覆盖的数据类型与嵌套结构,完整说明见 JSON 语法完全指南。
当 schema 推断和你想要的不一致时——比如你想让 version: 1.0 保持字符串但被解析为浮点数——可以用显式标签强制类型。
version: !!str 1.0 # 强制为字符串 "1.0"
count: !!int "42" # 即使加了引号也强制为整数 42
empty: !!null "" # 不是空字符串,而是显式的 null
!! 前缀表示"使用默认标签库中的标准标签"。自定义标签用单个 !(比如 CloudFormation 模板中的 !Ref),需要解析器专门支持。应用层面的 YAML 文件通常只需要知道 !!str 就够了。
多文档文件
一个 YAML 文件可以包含多个独立文档,用 --- 独占一行作为分隔。
---
kind: Service
name: web
---
kind: Deployment
name: web
replicas: 3
Kubernetes 中把多个清单合并到一个文件时就是这种形式。JSON 没有等价结构,转换时需要选择其中一个文档或者用外层数组包裹。
锚点、合并键、多文档的兼容性实测
锚点、合并键、多文档在 YAML 语法上都合法,但能不能用完全取决于你把它放在哪个环境里。4 种解析器和 Docker Compose 经过直接实测(2026-07-12,复现脚本在仓库 scripts/benchmarks/yaml-tool-acceptance/ 中),托管服务查阅了官方文档。
| 环境 | 锚点 & * | 合并键 <<: | 多文档 --- |
|---|---|---|---|
| js-yaml | 支持(实测) | 支持(实测) | load 报错。loadAll 支持(实测) |
| PyYAML | 支持(实测) | 支持(实测) | safe_load 报错。safe_load_all 支持(实测) |
| yaml (eemeli)(FormatArc 转换工具使用的解析器) | 支持(实测) | 默认不展开,<< 作为字面键保留(实测) | parse 报错。parseAllDocuments 支持(实测) |
| Docker Compose v5.3.0 | 支持(实测) | 支持(实测) | 多个文档合并为一个配置后接受(实测) |
| GitHub Actions | 2025-09-18 起支持在新标签页中打开 | 不支持 — 使用会报语法错误在新标签页中打开 | 官方文档未提及 |
| GitLab CI | 支持在新标签页中打开 | 支持在新标签页中打开 | 官方文档未提及 |
| Kubernetes (kubectl) | 官方文档未明确说明 | 官方文档未明确说明 | 支持在新标签页中打开 |
这张表有三个重点:
- GitHub Actions 支持锚点但不支持合并键。 2025 年 9 月锚点支持上线后,
<<:仍然报语法错误,所以从 GitLab CI 直接复制工作流会出问题。 - eemeli/yaml 默认遵循 YAML 1.2,而合并键是 YAML 1.1 的特性,所以它不会展开
<<:。解析不会报错,但{"<<": {...}}这个键会原样保留,变成隐蔽的 bug。 - 多文档取决于你调用哪个 API。 4 种解析器在单文档加载 API 下都会报错,切换到多文档专用 API 后就能正常处理。
实际场景中的 YAML 写法
不管你是写 5 行配置还是生产环境的部署清单,适用的语法规则是一样的。以下是 2026 年开发中最常见的 3 个场景。
Kubernetes Deployment 清单
最简的 Deployment 也同时涉及映射、序列、多行字符串和布尔值。spec.template.spec.containers 附近的缩进错位是最典型的失败原因。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27-alpine
ports:
- containerPort: 80
env:
- name: FEATURE_FLAG_NEW_HEADER
value: "true" # 故意加引号 — 裸的 true 会被当作布尔值
resources:
limits:
cpu: "500m"
memory: 256Mi
value: "true" 的引号是关键。去掉引号的话,Kubernetes 会接受布尔值,容器里拿到的可能是 True(Python 风格)或者直接启动失败。
GitHub Actions 工作流
GitHub Actions 工作流是深度嵌套的映射,run 块中多行 Shell 脚本很常见。|(字面量)和 >(折叠)的区分在这里特别有用。
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20" # 加引号保留末尾的 0
- name: Install
run: npm ci
- name: Test
run: |
npm run lint
npm run build
npm test -- --run
这里最常犯的错误是去掉 node-version: "20" 的引号。YAML 会把它转成整数 20,某些版本的 setup-node 可能不接受。凡是"看起来像数字但必须是字符串"的值,都要加引号。
Docker Compose 服务定义
Compose 文件是映射、序列、环境变量字典、绑定挂载字符串混合的短 YAML,适合练习识别缩进问题。
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80" # 加引号避免被解析为六十进制数
environment:
NGINX_HOST: example.com
NGINX_PORT: "80" # 必须加引号:环境变量值必须是字符串
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- api
api:
build: ./api
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 5s
retries: 3
两个陷阱:"8080:80" 不加引号的话 YAML 1.1 解析器可能把它当六十进制数读;environment: 下的值最终要以字符串形式传递,加引号更安全。
常见错误与各解析器的报错信息对比(实测)
以下是几乎每个开发者都会踩的 YAML 坑。
- 用 Tab 字符做缩进 — 肉眼看不见的 Tab 混入后极难定位
- 冒号后面没空格 —
key:value被当作一个字符串 - 缩进不一致 — 同一层级的元素必须缩进相同
- 不加引号的
NO、OFF、YES、ON被解析为布尔值(Norway problem) - 不加引号的值里包含冒号 —
time: 10:30可能被解析为六十进制数 - 块样式和流样式混用 — 解析器会困惑
- 同一映射中键重复 — 行为因实现而异
搜索这些错误时最麻烦的是:同一个错误在不同解析器中报完全不同的信息。下面把 6 种典型错误分别喂给 js-yaml、yaml (eemeli)、PyYAML,记录了实际输出的错误文本(2026-07-12 实测,含 ruamel.yaml 在内的 4 种解析器原始日志和复现脚本在仓库 scripts/benchmarks/yaml-syntax-errors/ 中)。
| 错误 | js-yaml 报错 | yaml (eemeli) 报错 | PyYAML 报错 |
|---|---|---|---|
| 用 Tab 缩进 | tab characters must not be used in indentation(第 2 行) | Tabs are not allowed as indentation(第 2 行) | found character '\t' that cannot start any token(第 2 行) |
| 缩进不一致(2 和 3 空格混用) | bad indentation of a mapping entry(第 3 行) | Nested mappings are not allowed in compact mappings(第 2 行) | mapping values are not allowed here(第 3 行) |
值中未加引号的 : (url: http://x.com: 8080) | bad indentation of a mapping entry(第 1 行第 24 列) | Nested mappings are not allowed in compact mappings(第 1 行第 6 列) | mapping values are not allowed here(第 1 行第 24 列) |
| 双引号未闭合 | unexpected end of the stream within a double quoted scalar(末行) | Missing closing "quote(第 2 行第 8 列) | while scanning a quoted scalar ... found unexpected end of stream(指向起始引号位置) |
未定义锚点的 *alias | unidentified alias "missing" | Unresolved alias (the anchor must be set before the alias): missing(不报行号) | found undefined alias 'missing' |
流式 [ 未闭合 | missed comma between flow collection entries(下一行) | Flow sequence in block collection must be sufficiently indented and end with a ](第 2 行) | while parsing a flow sequence ... expected ',' or ']' |
读这些错误的 3 个技巧。第一,PyYAML 的 mapping values are not allowed here 和 js-yaml 的 bad indentation of a mapping entry 看起来不相关,但它们指向同一个原因:在不能开始映射的位置出现了 : 。eemeli 的 Nested mappings are not allowed in compact mappings 是第三种说法。第二,不同解析器报告的行号不同:引号未闭合时 js-yaml 指向文件末尾,PyYAML 指向起始引号位置,所以要同时看报错行前后和引号起始位置。第三,eemeli 有时比 js-yaml 早报一行,因为它报告的是紧凑映射开始的位置而非出错的位置。
定位这类错误最快的办法是让解析器来读。不用安装任何东西,把 YAML 粘贴到 FormatArc 的 YAML to JSON 转换工具即可。合法的 YAML 会立即显示 JSON 结果,不合法则会提示语法错误并给出需要检查的行号。
"It is forbidden to specify block composed value at the same line as key" 错误解决
这个错误是 JetBrains/IntelliJ 系列 IDE(IntelliJ IDEA、PyCharm、GoLand、Rider、DataGrip)的 YAML 检查器(Inspection)输出的信息。原文定义在 YAMLBundle.properties在新标签页中打开 中的 annotator.same.line.composed.value.message。
意思只有一个:块集合(block collection)的起始和键在同一行上。查看检查器源码在新标签页中打开,它只检查两种形态——块序列的第一个元素和键在同一行,或块映射的第一个键值对和键在同一行。其他情况不会触发。
形态 1:块序列从键所在行开始。
# 触发 Inspection 的写法
key: - item1
- item2
修复:把第一个元素换到下一行。
key:
- item1
- item2
形态 2:块映射从键所在行开始。
# 触发 Inspection 的写法
key: sub: value
sub2: value2
修复:在冒号后换行。
key:
sub: value
sub2: value2
两种形态都是 YAML 规格上真正的语法错误,不是 IDE 的偏好问题。解析器同样会拒绝:yaml 包对形态 1 返回 Unexpected block-seq-ind on same line with key,对形态 2 返回 Nested mappings are not allowed in compact mappings。
这和重复键检查是不同的错误。 映射中键重复时,IDE 会报 Key 'x' is duplicated(同 bundle 中的 YAMLDuplicatedKeysInspection.duplicated.key)。如果提示键重复了,需要改键名或拆分父节点,和块集合的位置无关。
Helm 或 Jinja 模板中误报的情况: 检查器在设计上遇到模板语言注入的元素时会提前终止检查,所以正确编写的模板本不该被标记。如果仍然报错,那是已知的误报(如 IJPL-64437在新标签页中打开),文件本身不需要修改。
修复后粘贴到 FormatArc 的 YAML to JSON 工具确认块集合是否已正确换行。转换完全在浏览器内完成,你的数据不会上传到任何地方。
用 FormatArc 在浏览器中校验 YAML
FormatArc 的纯浏览器工具可以直接当作简易 YAML 校验器使用。


- YAML to JSON — 粘贴 YAML 获取 JSON 输出,出错时显示行号
所有处理都在浏览器本地完成。内部配置文件或包含密钥的数据可以放心粘贴调试,数据不会离开你的机器。
常见问题
YAML 缩进可以用 Tab 吗?
不行。YAML 规格只允许空格,Tab 字符在大多数解析器中会直接报语法错误。编辑 .yml 或 .yaml 文件时,把编辑器的 Tab 键设置为插入 2 个空格。
.yml 和 .yaml 有什么区别?
没有区别。两种扩展名在所有 YAML 解析器中的处理方式完全相同。官方规格推荐 .yaml,但 .yml 也很常见,完全没问题。
字符串必须加引号吗?
不需要。YAML 中大多数字符串可以直接写。只有当值会被误判为其他类型,或以 -、:、[、{、|、> 等特殊字符开头时,才需要加引号。
写了 version: 1.0 结果变成了 1,为什么?
YAML 把 1.0 解析为浮点数,部分序列化工具会把它输出为 1。想保持字符串形式就加引号:version: "1.0"。
缩进用几个空格合适?
2 个空格是惯例。Kubernetes、Docker Compose、GitHub Actions 等大多数官方示例都用 2 个空格。4 个空格也没问题,只要单个文件内保持一致就行。
不装任何东西怎么校验 YAML?
把文件内容粘贴到 FormatArc 的 YAML to JSON 转换工具即可。合法的 YAML 会立即输出 JSON,不合法则显示带行号的错误信息。
一个文件里能写多个 YAML 文档吗?
可以。用 --- 独占一行作为分隔符。Kubernetes 把多个清单打包到一个文件时就是标准做法。一个文件里可以放任意多个文档。
总结
- YAML 用缩进而非花括号表达结构
- 缩进只用空格,保持文件内一致
- 字符串只在会被误判时才加引号
- 注释、多行字符串、锚点能大幅提升配置文件的可读性和复用性
- 校验 YAML 语法最快的方式:粘贴到 FormatArc 的 YAML to JSON 工具即可