FormatArc 的 YAML to JSON 轉換器畫面,以行號標示語法錯誤的位置FormatArc 的 YAML to JSON 轉換器畫面,以行號標示語法錯誤的位置
作者: FormatArc 編輯部發布日期: 2026-09-02更新日期: 2026-09-02

YAML 語法教學:縮排規則、型別與常見錯誤解決

1 分鐘重點 — YAML 縮排與語法

  • 縮排只使用空白(空格),不得使用 Tab。2 格空格是事實上的標準。
  • key: value 中冒號後方必須有空格。key:value 會被視為單一的字串。
  • 列表使用 - (減號加空格),Mapping 使用 key: value
  • 可能被誤判為數字、布林值、日期的值要加引號:version: "1.0"
  • 想快速檢查錯誤,把 YAML 貼到 FormatArc 的 YAML to JSON 轉換器 就能看到附帶行號的錯誤訊息。

YAML 是什麼、用在哪裡

YAML(YAML Ain't Markup Language)是一種以人為本的純文字結構化資料格式。它涵蓋與 JSON 相同的資料模型——字串、數字、布林值、null、列表、Mapping——但語法不靠括號,而是以縮排(Indentation)表達層級結構。

如果你在做 DevOps 或雲端原生開發,應該已經接觸過 YAML:

  • Kubernetes manifest、Helm chart
  • Docker Compose 檔案
  • GitHub Actions、GitLab CI、CircleCI 的 workflow
  • Ansible playbook
  • OpenAPI 規格
  • 靜態網站產生器(Hugo、Jekyll、Eleventy)

如果你的 YAML 是用在 Markdown 檔案開頭的 frontmatter,YAML 轉 JSON 時有幾個特有的陷阱,詳見 Markdown frontmatter 格式與語法

這篇教學會用具體範例與新手常犯的錯誤清單,完整講解你實際會用到的 YAML 語法。想先了解 YAML 的概說,可看 YAML 是什麼;想比較 YAML 與 JSON 的差異,見 YAML JSON 比較;YAML 轉 JSON 的步驟則見 YAML 轉 JSON 指南

YAML 的三個基本元素

YAML 檔案中出現的所有資料,都是以下三種之一:

  • 標量(Scalar)— 字串、數字、布林值、null 等單一值
  • 序列(Sequence)— 有順序的列表
  • 映射(Mapping)— 鍵值對

這三種元素可以任意巢狀。Mapping 裡可以放列表,列表裡也可以放 Mapping。僅憑這些結構就能表達所有 JSON 相容的資料。

縮排規則

YAML 以縮排表達巢狀層級。需要記住的規則如下:

  • 只使用空格,不得使用 Tab 字元。Tab 在多數解析器中會觸發語法錯誤。
  • 一旦決定縮排寬度,整個檔案保持一致(通常是 2 格空格)。
  • 同一層級的項目必須縮排到相同的深度。
  • 沒有結尾括號,結構完全由縮排決定。

正確的範例:

database:
  host: localhost
  port: 5432
  credentials:
    user: admin
    password: secret

database 是一個 Mapping,包含 hostportcredentialscredentials 又是巢狀的 Mapping。用 2 格縮排就能一眼看清整體結構。

鍵值對(Mapping)的寫法

Mapping 以 key: value 的形式書寫。冒號後方必須有空格,key:value 省略空格的話會被當成單一的字串而非 Mapping。

name: Alice
age: 30
is_admin: true
bio: null

鍵通常是不含空格的簡單字串,但加上引號後也可以包含空格:

"full name": Alice Cooper

值可以是 YAML 支援的任何型別:標量、序列、Mapping。

列表(Sequence)的寫法

序列是在行首加上 - (減號加空格)來表示:

fruits:
  - apple
  - banana
  - cherry

列表中可以巢狀 Mapping:

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 結構字元開頭:[]{},*|>%@`"'#&!。開頭的 -:? 只有在緊接空格時才有問題。
  • 值中含有冒號加空格(: )的情形(會被誤判為 Mapping)
  • 想使用 \n\t 等跳脫序列

YAML 同時支援單引號(')與雙引號(")。雙引號會解析跳脫序列,單引號則保留原文。

escaped: "line1\nline2"
literal: 'line1\nline2'

實際會造成問題的字元可分為兩組,所屬的組別決定是否需要引號。下表是本站轉換工具所使用的解析器(yaml (eemeli) 2.8.3,YAML.parse 預設設定)的行為(2026-08-15 實測,重現腳本在儲存庫 scripts/benchmarks/yaml-quote-requirements/)。中間欄寫「安全」表示該字元不在值開頭時可以不加引號。

字元放在值開頭放在值中間單引號是否足夠雙引號
[ ] { } ,解析錯誤安全足夠可用
*解析錯誤(被當作別名)安全足夠可用
&不報錯,被當成錨點,值消失安全足夠可用
!不報錯,被當成 tag安全足夠可用
#不報錯,整段值被當作註解,變 null前面無空格時安全足夠可用
| >解析錯誤(被當作區塊標量)安全足夠可用
% @ `解析錯誤(保留字元)安全足夠可用
- ?單獨安全,緊接空格時解析錯誤安全足夠可用
:單獨安全,緊接空格時解析錯誤緊接空格時無論位置都會解析錯誤足夠可用
"解析錯誤安全足夠需以 \" 跳脫
'解析錯誤安全不夠。需以 '' 重複表示較穩妥

從表中可以得出兩點結論。第一,值中間危險的只有 : #,所以 url: http://example.com/a,b 不加引號也安全,其餘都是開頭字元的問題。第二,單引號除了單引號字元本身外幾乎都能安全包裹,這是在貼上 Windows 路徑或正規表示式時建議用單引號的原因。只有當你需要 \n\t 被解釋為真正的換行或 Tab 時才使用雙引號。

模板語法 {{ }} 放在值開頭會壞掉

Helm 模板或 Ansible 變數展開在未經渲染前直接交給 YAML 解析器,會踩到 { 被視為特殊字元的陷阱:

# 未渲染的 Helm 模板
image: {{ .Values.image }}

{{ 會被解析為兩層巢狀的 flow mapping,而且失敗的方式因解析器而異。實測結果(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 的 ${{ }}$ 開頭,不會被解析為 flow mapping,所以不會遇到這個問題。

多行字串

長文字區塊有兩種寫法。

Literal block(|)保留原始換行:

description: |
  這是第一行。
  這是第二行。

  空行後的第四行。

Folded scalar(>)把換行折成空格,適合在來源中折行書寫的長段落:

paragraph: >
  這句長句在來源中拆成
  好幾行書寫,但 YAML
  會把它折成一行處理。

Chomp 指標:strip、clip、keep

YAML 的區塊標量有一個 chomp 指標,決定尾部換行如何處理。指標寫在 |> 的緊後面。

指標行為範例
(無)— clip保留最後 1 個換行。預設值。|
- — strip移除所有尾部換行。|- >-
+ — keep保留所有尾部空行。|+ >+
clip: |
  line one
  line two
strip: |-
  line one
  line two
keep: |+
  line one
  line two

折疊格式(>>->+)也適用同樣的三種模式。|- 適合嵌入 JSON 或環境變數時不想要尾部換行的場合。|+ 適合產生 shell script 時尾部空行有意義的場合。

型別與解析器的型別推論

YAML 會從未加引號的值自動推斷型別。同樣的字面值,因解析器實現的 YAML 版本與使用的 schema 不同,可能被解讀為整數、浮點數、日期或字串。

integer: 42
hex: 0xFF              # 255(整數,16 進位)
octal: 0o17            # 15(整數,8 進位,YAML 1.2)
octal_legacy: 0644     # 420(整數,8 進位,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"        # 不是 8 進位整數

下表整理未加引號的字面值在現代 YAML 1.2 Core schema 的 loader(PyYAML、js-yaml、SnakeYAML 預設)與 YAML 1.1 的 loader(舊版 PyYAML、Symfony YAML)中分別會被解讀成什麼。多數出人意料的行為就藏在這兩欄的差異中。

字面值YAML 1.2 CoreYAML 1.1注意事項
42integer (42)integer (42)
0xFFinteger (255)integer (255)16 進位解析是規格定義的行為
0o17integer (15)(不識別)YAML 1.2 限定
0644integer (644)integer (420, 8 進位)檔案權限解讀因版本而異
1e3float (1000.0)float (1000.0)部分工具顯示時會省略 .0
.inf / -.inffloat (±Infinity)float (±Infinity)無法序列化為 JSON
.nanfloat (NaN)float (NaN)無法序列化為 JSON
2026-04-13stringdate(日期物件)JSON 與 YAML 來回轉換時型別會變
2026-04-13T09:30Zstringtimestamp同樣的問題
true / falsebooleanboolean
yes / no / on / offstringboolean「Norway problem」
NOstringboolean (false)下一節詳細說明
~ / null / Null / NULLnullnull大小寫皆解讀為 null
1.0float (1.0)float (1.0)部分工具會重新序列化為 1

如果你的解析器接近正式環境,最右欄的項目都應視為潛在 bug。確認手邊 loader 使用哪個版本最快的方法,是把具代表性的檔案貼到 FormatArc 的 YAML to JSON 轉換器 看 JSON 輸出。"NO" 還是 false"2026-04-13" 還是 ISO 日期字串,一目瞭然。

兩欄差異的根源在於 YAML 1.1 與 1.2 對型別推論的定義不同。YAML 1.1 包含廣泛的隱含型別 tag,包括時間戳記、60 進位(sexagesimal)、以及導致 Norway problem 的布林值詞彙。YAML 1.2 改用更嚴格的 Core schema在新分頁中開啟,布林值限定為 truefalse(規格的 Core 正規表示式也接受首字母大寫或全大寫的 True/TRUE/False/FALSE,但不再接受 yes/no/on/off),取消隱含時間戳記與 60 進位 tag,其餘則跟隨 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"]YESONOFFYN 以及大小寫變體也會依解析器不同觸發同樣的問題。

解決方法就是對可能被誤讀的值加上引號:

countries:
  - "DE"
  - "FR"
  - "NO"
  - "SE"

YAML 1.2 雖然把布林值限定為 true / false,但實務上多數工具仍然內嵌 1.1 時代的 loader。國家代碼、語言代碼、版本字串、短標識符都應該加上引號。想確認解析器相容性的話,把設定貼到 FormatArc 的 YAML to JSON 轉換器 就能立刻看到 "NO" 是否保留為字串。

嚴格的現代布林值集合見 YAML 1.2.2 規格在新分頁中開啟,舊工具實際實現的規則見 YAML 1.1 規格在新分頁中開啟

註解

註解從 # 開始到行末為止。可以獨立成一行,也可以跟在值後面:

# 上游請求的最大重試次數
retries: 3  # 再大就會超過上游 timeout

註解是 YAML 相比 JSON 在設定檔上最大的優勢之一。與其寫「這是什麼」,不如寫「為什麼設這個值」。轉成 JSON 後所有註解都會消失,所以建議以 YAML 作為來源檔管理。如果還是需要在 JSON 中保留註解,可看 JSON 註解方式 的 4 種替代方法。

錨點與別名:重複利用

YAML 可以用 & 定義錨點(Anchor),用 * 引用別名(Alias),並以 <<: 合併鍵(Merge key)把 Mapping 作為預設值引入。

defaults: &defaults
  adapter: postgres
  host: db.internal
  pool: 5

development:
  <<: *defaults
  database: myapp_dev

production:
  <<: *defaults
  database: myapp_prod
  pool: 20

production 繼承 defaults 的設定,只覆寫 pool 的值。不用複製貼上就能在各環境間共用設定。

合併鍵(<<:)共用設定

<<: 合併鍵是錨點最好用的搭配。它把一個 Mapping 的鍵引入另一個 Mapping,讓「跟那個一樣但只有這裡要覆寫」的結構不用重複寫。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

使用時有兩點要注意:

  • 合併鍵只做 1 層合併(shallow merge)。巢狀 Mapping(如上方的 environment)不會做深合併(deep merge),而是整體覆寫。
  • 合併鍵是 YAML 1.1 的規格功能。嚴格的 YAML 1.2 解析器可能忽略它,但 Docker Compose 與 GitLab CI 仍支援 1.1 語意所以不會出問題。

Schema 與 tag:YAML 如何決定型別

YAML 1.2 定義了三個控制未加引號字面值解讀方式的 schema:

  • FailSafe — 只支援字串、Mapping、Sequence。最安全的 schema,其餘一律視為字串。很少被設為預設。
  • JSON — 支援 JSON 相容型別(字串、整數、浮點數、布林值、null、Mapping、Sequence),與 JSON.parse 產出一致。
  • Core — 一般預設。在 JSON 基礎上加上前述表中的型別推論規則(16 進位、8 進位、.inf.nan~)。

多數解析器預設搭載 Core(PyYAML 的 safe_load、js-yaml 預設值、SnakeYAML 的 SafeConstructor)。Symfony YAML 則仍以 YAML 1.1 語意為預設。

當 schema 推斷出錯——例如你打算寫字串但 version: 1.0 被解析為浮點數——可以用明確的 tag 強制型別:

version: !!str 1.0       # 強制為字串 "1.0"
count: !!int "42"        # 即使加了引號也強制為整數 42
empty: !!null ""         # 空字串改為明確的 null

!! 前綴表示使用預設 tag 庫的標準 tag。自訂 tag 用單一 !(例如 AWS CloudFormation 的 !Ref),需要解析器端有對應的實作。應用程式層的 YAML 檔案通常只要認識 !!str 就能處理絕大部分型別陷阱。

多文件(Multi-document)

一個 YAML 檔案可以包含多份獨立文件,以 --- 獨立行作為分隔:

---
kind: Service
name: web
---
kind: Deployment
name: web
replicas: 3

這是 Kubernetes 把多份 manifest 包在同一個檔案時的標準格式。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 Actions2025-09-18 起支援在新分頁中開啟不支援 — 使用會語法錯誤在新分頁中開啟官方文件未提及
GitLab CI支援在新分頁中開啟支援在新分頁中開啟官方文件未提及
Kubernetes (kubectl)官方文件未明確說明官方文件未明確說明支援在新分頁中開啟

這張表有三個重點:

  • GitHub Actions 支援錨點但不支援合併鍵。2025 年 9 月加入錨點支援後 <<: 仍是語法錯誤,所以 GitLab CI 的 workflow 不能直接搬過來。
  • eemeli/yaml 預設遵循 YAML 1.2,因此 YAML 1.1 規格的合併鍵不會被自動展開。不報錯反而危險,{"<<": {...}} 這個鍵會靜默保留,變成不预期的 bug。
  • 多文件取決於使用哪個 API 函式。4 種解析器在單文件讀取 API 中都會報錯,改用多文件專用 API 就正常。

實際使用 YAML 的三個場景

無論幾行的設定檔還是大規模部署 manifest,適用的語法規則都一樣。以下是 2026 年開發中 YAML 出現頻率最高的三個場景。

Kubernetes Deployment manifest

最小化的 Deployment 就同時用到 Mapping、Sequence、多行字串、布林值。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 workflow

GitHub Actions 的 workflow 是深度巢狀的 Mapping,run 區塊常見多行 shell 指令。|(literal)與 >(folded)的差異在這裡會派上用場。

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 檔案混合 Mapping、Sequence、環境變數字典、bind mount 字串,短到可以完整貼出,是練習辨認縮排問題的好對象。

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"               # 加引號避免被解讀為 60 進位
    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 解析器可能把它當作 60 進位解析;environment: 下方的值最終都是以字串傳遞,所以加引號比較安全。

常見錯誤與各解析器的錯誤訊息(實測)

多數開發者都踩過的 YAML 陷阱:

  • 用 Tab 字元縮排 — 看不見的 Tab 混入時很難找原因
  • 冒號後沒有空格 — key:value 被當成單一的字串
  • 縮排寬度不一致 — 同層項目必須同一深度
  • 未加引號的 NOOFFYESON 被轉為布林值(Norway problem)
  • 未加引號的值中包含冒號 — time: 10:30 可能被解讀為 60 進位
  • 區塊格式與流程格式混用 — 解析器可能無法預期
  • 同一 Mapping 中使用重複鍵 — 行為取決於實作

搜尋這些錯誤時最頭痛的地方:同一個錯誤在不同解析器中回報完全不同的訊息。我們把 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: 8080bad 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 ']'

解讀這些訊息有三個技巧。第一,PyYAML 的 mapping values are not allowed here 與 js-yaml 的 bad indentation of a mapping entry 看似不同的錯誤,實際上都是「在 Mapping 不該出現的位置有 : 」,eemeli 的 Nested mappings are not allowed in compact mappings 是同一診斷的第三種說法。第二,各解析器指出的行號不同:引號未關閉時 js-yaml 指向串流結尾,PyYAML 指向開頭引號位置,所以要同時檢查錯誤行的前後 1 行與引號起始位置。第三,eemeli 有時比 js-yaml 早 1 行指出位置,因為它回報的是 compact mapping 開始的位置而非壞掉的位置。

要最快找到這些錯誤的方法就是讓解析器去讀。不安裝任何東西就能做的話,把 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)從鍵的同一行開始了。inspection 的原始碼在新分頁中開啟顯示,檢查對象只有兩種形態:block sequence 的第一個項目與鍵在同一行,或 block mapping 的第一個鍵值與鍵在同一行。

形態 1:block sequence 從鍵所在行開始。

# 會觸發 inspection 的寫法
key: - item1
     - item2

解法:把第一個項目移到下一行。

key:
  - item1
  - item2

形態 2:block mapping 從鍵所在行開始。

# 會觸發 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

與重複鍵的 inspection 是不同的錯誤。 Mapping 的鍵重複時會顯示 Key 'x' is duplicated(同 bundle 的 YAMLDuplicatedKeysInspection.duplicated.key)。如果 IDE 告訴你鍵重複了,解法是改鍵名或調整父節點,與區塊集合的位置無關。

Helm 或 Jinja 模板中出現此錯誤時: inspection 在偵測到模板語言注入元素時會提前結束檢查,所以正確撰寫的模板原本不應該被標記。如果仍然出現,屬於已知的假陽性(false positive,如 IJPL-64437在新分頁中開啟),檔案本身不需要修改。

修正後把檔案貼到 YAML to JSON 確認區塊集合是否已正常處理。所有轉換都在瀏覽器內完成,輸入的資料不會被上傳。

用 FormatArc 在瀏覽器中驗證 YAML

FormatArc 的瀏覽器端工具可以直接當作輕量 YAML linter 使用:

FormatArc 的 YAML to JSON 轉換器畫面,以行號標示語法錯誤的位置FormatArc 的 YAML to JSON 轉換器畫面,以行號標示語法錯誤的位置

  • YAML to JSON — 貼上 YAML 取得 JSON 輸出,有錯誤時附行號顯示
  • JSON to YAML — 從 JSON 出發學習對應的 YAML 結構
  • JSON Formatter — 美化整理轉換後的 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 把多份 manifest 包在同一個檔案中的標準做法。

總結

  • YAML 以縮排表達結構,不用括號
  • 縮排只用空格,保持一致
  • 字串只在會被誤判時才加引號
  • 註解、多行字串、錨點讓設定檔可讀性與重用性大幅提升
  • 語法驗證最快的方式是把 YAML 貼到 FormatArc 的 YAML to JSON 工具