{"record":{"id":"27f51fad2da4f1eb","repo":"kovidgoyal/kitty","slug":"ignoring-geninclude-directive-for-security","errorCode":null,"errorMessage":"Ignoring geninclude directive for security","messagePattern":"Ignoring geninclude directive for security","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kitty/conf/utils.py","lineNumber":319,"sourceCode":"        elif key == 'envinclude':\n            from fnmatch import fnmatchcase\n\n            for x in os.environ:\n                if fnmatchcase(x, val):\n                    with currently_parsing.set_file(f'<env var: {x}>'):\n                        _parse(\n                            NamedLineIterator(os.path.join(base_path_for_includes, ''), iter(os.environ[x].splitlines())),\n                            parse_conf_item,\n                            ans,\n                            memory,\n                            accumulate_bad_lines,\n                            effective_config_lines,\n                            allow_geninclude=allow_geninclude,\n                        )\n            return\n        elif key == 'geninclude':\n            if not allow_geninclude:\n                log_error('Ignoring geninclude directive for security')\n                return\n            if not os.path.isabs(val):\n                val = os.path.join(base_path_for_includes, val)\n            if not memory.seen(val):\n                try:\n                    lines = geninclude(val)\n                except FileNotFoundError as e:\n                    if e.filename == val:\n                        log_error(f'Could not find the geninclude file: {val}, ignoring')\n                    else:\n                        raise\n                else:\n                    with currently_parsing.set_file(f'<get: {val}>'):\n                        _parse(\n                            NamedLineIterator(os.path.join(base_path_for_includes, ''), iter(lines)),\n                            parse_conf_item,\n                            ans,\n                            memory,","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/conf/utils.py#L301-L337","documentation":"A `geninclude` directive (run a program that generates config lines) appeared in a config file parsed with allow_geninclude=False — typically an included file — so kitty refuses to execute it.","triggerScenarios":"Putting geninclude in a file pulled in via include/globinclude, or in any context where generated includes are disallowed for security.","commonSituations":"Users trying to share a generated config through includes; geninclude only works in the top-level kitty.conf with a compiled-in kitty.","solutions":["Move the geninclude directive to the top-level kitty.conf","Use static `include`/`globinclude` for sub-files"],"exampleFix":"# in included file (blocked)\ngeninclude my-gen.py\n# instead put in kitty.conf\ngeninclude my-gen.py","handlingStrategy":"validation","validationCode":"if directive == 'geninclude' and not is_top_level_config(path): skip_with_warning()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep geninclude only in top-level kitty.conf","Use include/globinclude for sub-files"],"tags":["kitty","config","geninclude","security"],"backgroundTag":"config-directive-not-allowed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}