{"record":{"id":"7f55ac6daafacf79","repo":"kovidgoyal/kitty","slug":"failed-to-load-cmd-check-function-from-path-with","errorCode":null,"errorMessage":"Failed to load cmd check function from {path} with error: {e}","messagePattern":"Failed to load cmd check function from (.+?) with error: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kitty/remote_control.py","lineNumber":93,"sourceCode":"            )\n            return {}\n    return pcmd\n\n\nclass CMDChecker:\n    def __call__(self, pcmd: dict[str, Any], window: Optional['Window'], from_socket: bool, extra_data: dict[str, Any]) -> bool | None:\n        return False\n\n\n@lru_cache(maxsize=64)\ndef is_cmd_allowed_loader(path: str) -> CMDChecker:\n    import runpy\n\n    try:\n        m = runpy.run_path(path)\n        func: CMDChecker = m['is_cmd_allowed']\n    except Exception as e:\n        log_error(f'Failed to load cmd check function from {path} with error: {e}')\n        func = CMDChecker()\n    return func\n\n\n@lru_cache(maxsize=1024)\ndef fnmatch_pattern(pat: str) -> 're.Pattern[str]':\n    from fnmatch import translate\n\n    return re.compile(translate(pat))\n\n\ndef constant_time_lookup(passwords: dict[str, T], pw: str) -> T | None:\n    result = None\n    c = hmac.compare_digest\n    for k, v in passwords.items():\n        if c(k, pw):\n            result = v\n    return result","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/remote_control.py#L75-L111","documentation":"kitty failed to import the user-supplied Python module (path from --remote-control-password-file style config, i.e. the config option pointing to a file defining is_cmd_allowed). It falls back to a default checker that will deny commands, so remote control effectively stops working.","triggerScenarios":"runpy.run_path(path) or the m['is_cmd_allowed'] lookup raises — syntax error, missing is_cmd_allowed function, bad path — in is_cmd_allowed_loader.","commonSituations":"Typo in the path config, Python syntax errors in the auth script, script written for an older kitty API, or missing module-level imports in the script.","solutions":["Test the file standalone: python3 /path/to/auth.py and fix any syntax/import errors","Ensure the file defines a function named exactly is_cmd_allowed(pcmd, window, from_socket, extra_data) -> Optional[bool]","Fix the path configured in kitty.conf so it points to the real file"],"exampleFix":"# auth.py must define:\ndef is_cmd_allowed(pcmd, window, from_socket, extra_data):\n    return pcmd.get('cmd') == 'send-text'","handlingStrategy":"try-catch","validationCode":"import runpy\nm = runpy.run_path(path)\nassert callable(m.get('is_cmd_allowed')), 'is_cmd_allowed missing or not callable'","typeGuard":"def loads_auth_module(path: str):\n    m = runpy.run_path(path)\n    f = m.get('is_cmd_allowed')\n    return f if callable(f) else None","tryCatchPattern":"try:\n    checker = loads_auth_module(path) or default_deny\nexcept Exception:\n    checker = default_deny  # fail closed","preventionTips":["Smoke-test the auth script with python3 after every kitty upgrade","Name the function exactly is_cmd_allowed and keep its signature stable"],"tags":["kitty","remote-control","auth-callback","plugin-load"],"backgroundTag":"plugin-module-load-failed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}