Common Mistakes
Common errors and solutions when writing Workflows — YAML syntax, required fields, type errors, unsupported features
This document covers common mistakes and solutions when writing Workflow YAML files.
YAML Syntax Errors
Using Tab Characters
YAML only allows spaces for indentation. Using tab characters will cause a parsing error.
# ❌ Tab character — causes error
name: test-workflow
triggers:
push:
branches: ["main"]
jobs:
build:
steps:
- name: Test
run: echo "test"
env: # ← This line is indented with a tab
KEY: value# ✅ Indent with spaces
name: test-workflow
triggers:
push:
branches: ["main"]
jobs:
build:
steps:
- name: Test
run: echo "test"
env:
KEY: valueUse an editor setting that automatically converts tabs to spaces. Tab characters in YAML files always cause errors.
Duplicate Keys
Declaring the same key twice at the same level causes an error.
# ❌ name key declared twice
name: test-workflow
name: duplicate-name # Duplicate key error
triggers:
push:
branches: ["main"]Incorrect Indentation
# ❌ steps indented as a dictionary instead of a list
jobs:
build:
steps:
name: Test # ← Missing `-`
run: echo "test"
# ✅ List items start with `-`
jobs:
build:
steps:
- name: Test
run: echo "test"Missing Required Fields
Missing name
# ❌ name field is missing
triggers:
push:
branches: ["main"]
jobs:
build:
steps:
- name: Test
run: echo "test"
# ✅ name is required
name: my-workflow
triggers:
push:
branches: ["main"]
jobs:
build:
steps:
- name: Test
run: echo "test"Missing jobs
# ❌ jobs field is missing
name: test-workflow
triggers:
push:
branches: ["main"]
# jobs is missing → errorMissing steps
# ❌ steps field is missing
name: test-workflow
triggers:
push:
branches: ["main"]
jobs:
build:
# steps is missing → error
# ✅ At least 1 step is required
jobs:
build:
steps:
- name: hello
run: echo "Hello"Empty steps List
# ❌ steps is an empty list
jobs:
build:
steps: [] # At least 1 required
# ✅ At least 1 step
jobs:
build:
steps:
- name: hello
run: echo "Hello"Type Errors
branches as a String
branches must be a list.
# ❌ branches is a string
triggers:
push:
branches: main # String → error
# ✅ branches is a list
triggers:
push:
branches: [main] # or ["main"]needs as a String
needs must also be a list.
# ❌ needs is a string
jobs:
deploy:
needs: build # String → error
steps: [...]
# ✅ needs is a list
jobs:
deploy:
needs: [build]
steps: [...]Job Value is Not a Dictionary
# ❌ Job value is a string
jobs:
build: "not a dict" # Error
# ✅ Job is a dictionary
jobs:
build:
steps:
- name: test
run: echo "test"Step name is Not a String
# ❌ name is a number
steps:
- name: 123 # Number → error
run: echo "test"
# ✅ name is a string
steps:
- name: step-123
run: echo "test"Job ID Rule Violations
Job ID with Spaces
# ❌ Job ID contains spaces
jobs:
"build job": # Contains spaces → error
steps: [...]
# ✅ Allowed characters: [a-zA-Z0-9_-]
jobs:
build-job:
steps: [...]Job ID with Special Characters
# ❌ Special characters
jobs:
"build!": # Contains ! → error
steps: [...]
"deploy@prod": # Contains @ → error
steps: [...]
# ✅ Only letters, numbers, hyphens, and underscores
jobs:
build:
deploy-prod:
deploy_prod:Step-related Errors
Step Missing name
Object-style Steps require a name.
# ❌ Only run without name
steps:
- run: echo "test" # name is required
# ✅ Include name
steps:
- name: test
run: echo "test"
# ✅ Shorthand syntax (string) does not require name
steps:
- echo "test"Step Missing Both run and uses
# ❌ Nothing to execute
steps:
- name: Test
env:
KEY: value # No run or uses
# ✅ Either run or uses is required
steps:
- name: Test
run: echo "test"
env:
KEY: valueUsing run and uses Simultaneously
# ❌ run and uses are mutually exclusive
steps:
- name: Checkout
uses: "collabops/checkout@v2"
run: echo "test" # Cannot use both
# ✅ Separate into different Steps
steps:
- name: Checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: Test
run: echo "test"Duplicate Step Names
# ❌ Same name within a Job
steps:
- name: Test
run: echo "test1"
- name: Test # Duplicate → error
run: echo "test2"
# ✅ Use unique names
steps:
- name: test-unit
run: echo "test1"
- name: test-integration
run: echo "test2"Expression Errors
Using Expression as an env Key
# ❌ Expressions cannot be used as keys
steps:
- name: Test
run: echo "test"
env:
${{ secrets.KEY }}: value # Expression as key → error
# ✅ Keys are literals, Expressions go in values
steps:
- name: Test
run: echo "test"
env:
API_KEY: "${{ secrets.KEY }}"Using Unsupported Features
The following fields are not currently supported. Using them will either be ignored or cause an error.
shell (Unsupported)
# ❌ shell field not supported
steps:
- name: Test
run: echo "hi"
shell: bash # Not supported
# ✅ Remove shell field
steps:
- name: Test
run: echo "hi"working-directory (Constraints)
working-directory is supported but has the following constraints:
# ❌ Absolute path or .. is not allowed
steps:
- name: Test
run: echo "test"
working-directory: /absolute/path # Must be relative
- name: Test2
run: echo "test"
working-directory: ../parent # Cannot contain ..
# ✅ Use relative paths
steps:
- name: Test
run: echo "test"
working-directory: subdir
- name: Test2
run: echo "test"
working-directory: packages/frontendtimeout-minutes (Constraints)
timeout-minutes is supported but has the following constraints:
# ❌ timeout-minutes must be a positive integer
steps:
- name: Test
run: npm test
timeout-minutes: -1 # Must be positive
- name: Test2
run: npm test
timeout-minutes: 0 # Must be positive
# ✅ Positive integer value
steps:
- name: Test
run: npm test
timeout-minutes: 30timeout-minutes is only supported with run. It cannot be used with uses.
matrix
# ❌ matrix not supported
jobs:
test:
strategy:
matrix: # Not supported
node: [16, 18, 20]
steps: [...]
# ✅ Separate into individual Jobs
jobs:
test-node-16:
steps:
- name: test
run: npm test
image: node:16
test-node-18:
steps:
- name: test
run: npm test
image: node:18
test-node-20:
steps:
- name: test
run: npm test
image: node:20Trigger-related Errors
Missing triggers
# ❌ triggers is missing
name: test-workflow
jobs:
build:
steps:
- name: test
run: echo "test"
# ✅ triggers is required
name: test-workflow
triggers:
push:
branches: [main]
jobs:
build:
steps:
- name: test
run: echo "test"Missing branch in schedule
# ❌ branch is required
triggers:
schedule:
cron: ["0 0 * * *"] # branch is missing → error
# ✅ Include branch
triggers:
schedule:
branch: main
cron: ["0 0 * * *"]Missing cron in schedule
# ❌ cron is required
triggers:
schedule:
branch: main # cron is missing → error
# ✅ Include cron (at least 1)
triggers:
schedule:
branch: main
cron: ["0 0 * * *"]Using paths and paths-ignore Together
# ❌ Cannot use both
triggers:
push:
branches: [main]
paths: [src/**]
paths-ignore: [docs/**] # Cannot use with paths
# ✅ Use only one
triggers:
push:
branches: [main]
paths: [src/**, "!docs/**"] # Use negation pattern to excludeChecklist
Review the following items after writing your Workflow:
Are all required fields name, triggers, and jobs present?
Does each Job have at least 1 steps?
Does each Step have a name? (Except shorthand)
Does each Step have either run or uses?
Are run and uses not used simultaneously?
Are branches and needs in list format?
Do Job IDs contain no spaces or special characters?
Are Step names within the same Job unique?
Are spaces used instead of tab characters?
Are Expressions not used as env keys?
Are unsupported fields like shell not used?
Is working-directory a relative path without ..?
Is timeout-minutes a positive integer and only used with run?