CollabOps
CI/CDTroubleshooting

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: value

Use 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 → error

Missing 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 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: value

Using 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/frontend

timeout-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: 30

timeout-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:20

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 exclude

Checklist

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?

Table of Contents