kovidgoyal/kitty · error

Too many nested include directives while processing config f

Error message

Too many nested include directives while processing config file: %s

What it means

The config file parser limits include directives to 32 levels of nesting to prevent infinite recursion. When parsing an include chain deeper than 32 files, it aborts with this error naming the file being processed.

Source

Thrown at tools/config/api.go:128

		}
		return os.Getenv(k)
	})
}

const OverridesFileName = "<overrides>"

func (self *ConfigParser) parse(scanner Scanner, name, base_path_for_includes string, depth int) error {
	if self.seen_includes[name] { // avoid include loops
		return nil
	}
	self.seen_includes[name] = true
	if self.AllIncludedFiles != nil && name != OverridesFileName {
		self.AllIncludedFiles.Add(name)
	}

	recurse := func(r io.Reader, nname, base_path_for_includes string) error {
		if depth > 32 {
			return fmt.Errorf("Too many nested include directives while processing config file: %s", name)
		}
		escanner := bufio.NewScanner(r)
		return self.parse(escanner, nname, base_path_for_includes, depth+1)
	}

	make_absolute := func(path string) (string, error) {
		if path == "" {
			return "", fmt.Errorf("Empty include paths not allowed")
		}
		if !filepath.IsAbs(path) {
			path = filepath.Join(base_path_for_includes, path)
		}
		return path, nil
	}

	lnum := 0
	next_line_num := 0
	next_line := ""

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Check the named file and trace its include chain for a cycle
  2. Flatten the include hierarchy by inlining deeply nested includes
  3. Use the AllIncludedFiles set / logs to identify which files form the loop and break it

Example fix

# before
# a.conf
include b.conf
# b.conf
include a.conf
# after
# a.conf
include b.conf
# b.conf
map ctrl+a>1 load_config_file
Defensive patterns

Strategy: validation

Validate before calling

seen := map[string]bool{}
var check func(path string, depth int) error
check = func(path string, depth int) error {
    if depth > 32 { return fmt.Errorf("include chain too deep at %s", path) }
    if seen[path] { return fmt.Errorf("circular include at %s", path) }
    seen[path] = true
    return nil // recurse into included files similarly
}

Prevention

When it happens

Trigger: A chain of config files where each includes the next (directly or cyclically) exceeding depth 32, e.g. a.conf includes b.conf includes c.conf ... or two files that include each other.

Common situations: Circular includes (file A includes B which includes A), or over-modularized configs where shared snippets include other snippets repeatedly.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/b86ad02e28c4e8e8. Report an issue: GitHub.