air-verse/air · error

build.rules[%d] (%s): at least one of include_dir, include_e

Error message

build.rules[%d] (%s): at least one of include_dir, include_ext or include_file is required

What it means

normalizeRules requires each `build.rules` entry to declare at least one matcher — include_dir, include_ext, or include_file — otherwise the rule could never match anything and is rejected. The error names the rule index and name.

Source

Thrown at runner/config.go:180

func (r *cfgRule) delay() time.Duration {
	if r.Delay <= 0 {
		return 1000 * time.Millisecond
	}
	return time.Duration(r.Delay) * time.Millisecond
}

func (c *cfgBuild) normalizeRules(root string) error {
	for i := range c.Rules {
		r := &c.Rules[i]
		if r.Name == "" {
			r.Name = fmt.Sprintf("rule-%d", i)
		}
		if r.Cmd == "" {
			return fmt.Errorf("build.rules[%d] (%s): cmd is required", i, r.Name)
		}
		if len(r.IncludeDir) == 0 && len(r.IncludeExt) == 0 && len(r.IncludeFile) == 0 {
			return fmt.Errorf("build.rules[%d] (%s): at least one of include_dir, include_ext or include_file is required", i, r.Name)
		}
		r.includeDirAbs = r.includeDirAbs[:0]
		for _, dir := range r.IncludeDir {
			dir = cleanPath(dir)
			if dir == "" {
				continue
			}
			abs := filepath.Clean(dir)
			if !filepath.IsAbs(abs) {
				abs = filepath.Join(root, abs)
			}
			r.includeDirAbs = append(r.includeDirAbs, filepath.Clean(abs))
		}
		r.regexCompiled = r.regexCompiled[:0]
		for _, expr := range r.ExcludeRegex {
			re, err := regexp.Compile(expr)
			if err != nil {
				return fmt.Errorf("build.rules[%d] (%s): failed to compile regex %q: %w", i, r.Name, expr, err)

View on GitHub (pinned to 71ea1dee05)

Solutions

  1. Add at least one matcher, e.g. include_ext = [".go"] or include_dir = ["cmd"]
  2. Delete the rule if it is not needed
  3. Check for typos in the include_* key names

Example fix

// before (.air.toml)
[[build.rules]]
name = "tests"
cmd = "go test ./..."
// after (.air.toml)
[[build.rules]]
name = "tests"
cmd = "go test ./..."
include_ext = ["_test.go"]
Defensive patterns

Strategy: validation

Validate before calling

# each rules block must set include_dir, include_ext or include_file
grep -A5 '^\\[\\[build.rules\\]\\]' .air.toml | grep -Eq 'include_(dir|ext|file)' || echo "rule missing include_*"

Prevention

When it happens

Trigger: Loading a `.air.toml` whose `[[build.rules]]` has a cmd but none of include_dir / include_ext / include_file set (all empty arrays or absent).

Common situations: Writing a rule with only cmd and name and forgetting the matcher; commenting out the include_ext line; mispelling the key (e.g. include_ex) so it parses as empty.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of air-verse/air@71ea1dee05 (2026-08-31). Data as JSON: /api/errors/bad88d904487fab7. Report an issue: GitHub.