{"record":{"id":"841e9db3e3659203","repo":"getredash/redash","slug":"0-is-not-configured-as-a-supported-import-modu","errorCode":null,"errorMessage":"'{0}' is not configured as a supported import module","messagePattern":"'(.+?)' is not configured as a supported import module","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"redash/query_runner/python.py","lineNumber":156,"sourceCode":"                    sys.path.append(p)\n\n        if self.configuration.get(\"additionalBuiltins\", None):\n            for b in self.configuration[\"additionalBuiltins\"].split(\",\"):\n                if b not in self.safe_builtins:\n                    self.safe_builtins += (b,)\n\n    def custom_import(self, name, globals=None, locals=None, fromlist=(), level=0):\n        if name in self._allowed_modules:\n            m = None\n            if self._allowed_modules[name] is None:\n                m = importlib.import_module(name)\n                self._allowed_modules[name] = m\n            else:\n                m = self._allowed_modules[name]\n\n            return m\n\n        raise Exception(\"'{0}' is not configured as a supported import module\".format(name))\n\n    @staticmethod\n    def custom_write(obj):\n        \"\"\"\n        Custom hooks which controls the way objects/lists/tuples/dicts behave in\n        RestrictedPython\n        \"\"\"\n        return full_write_guard(obj)\n\n    @staticmethod\n    def custom_get_item(obj, key):\n        return obj[key]\n\n    @staticmethod\n    def custom_get_iter(obj):\n        return iter(obj)\n\n    @staticmethod","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/query_runner/python.py#L138-L174","documentation":"The Python query runner executes user code in RestrictedPython with a whitelist of importable modules (set via the allowed import modules config). custom_import() raises this Exception when import/from-import requests a module not on that whitelist — it is a sandbox restriction, not a missing package.","triggerScenarios":"Running a Python query containing e.g. `import requests` when requests is not in the REDASH_ENABLED_IMPORT_MODULES / allowed modules list for the runner worker.","commonSituations":"Admin hasn't extended allowed modules after users request numpy/pandas/requests; module name case mismatch; or attempting to import a submodule of an allowed top-level package when only the top-level was enabled.","solutions":["Add the module to the Python runner's allowed import modules setting/environment and restart workers","Import only whitelisted modules in the query; restructure the query to use already-available libraries (pandas is typically available)","Check exact module name spelling/case matches the whitelist entry","Use a different data source / external script if the module genuinely can't be allow-listed for security reasons"],"exampleFix":"# before\nimport requests  # not whitelisted\n\n# after (after admin adds 'requests' to allowed import modules, or:)\nimport pandas as pd  # already allowed","handlingStrategy":"validation","validationCode":"allowed = set(get_allowed_import_modules())  # from runner config\nneeded = scan_imports(query_code)  # ast-based import scanner\nmissing = needed - allowed\nassert not missing, f'ask admin to allow: {missing}'","typeGuard":"def import_ok(module: str, allowed: set) -> bool:\n    top = module.split('.')[0]\n    return top in allowed","tryCatchPattern":null,"preventionTips":["Maintain a documented list of whitelisted modules for query authors","Static-scan Python queries for imports before save/deploy","Keep RestrictedPython and the allow-list in sync across worker upgrades"],"tags":["redash","python-runner","restrictedpython","sandbox","imports"],"backgroundTag":"sandbox-import-not-allowed","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}