{"record":{"id":"8604eecee8386cfb","repo":"influxdata/influxdb","slug":"call-site-contains-null-bytes","errorCode":null,"errorMessage":"call site contains null bytes","messagePattern":"call site contains null bytes","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"influxdb3_py_api/src/system_py.rs","lineNumber":294,"sourceCode":"/// retrieves the function.\nfn load_plugin_function<'py>(\n    py: Python<'py>,\n    code: &str,\n    plugin_root: Option<&Path>,\n    call_site: &str,\n    missing_fn_error: ExecutePluginError,\n) -> Result<Bound<'py, PyAny>, ExecutePluginError> {\n    if let Some(root_path) = plugin_root {\n        load_function_from_module(py, root_path, call_site, missing_fn_error)\n    } else {\n        // Create isolated globals for this plugin execution. Without this, single-file\n        // plugins would share __main__'s namespace and could overwrite each other's\n        // function definitions during concurrent execution.\n        let globals = PyDict::new(py);\n        let code = CString::new(code)\n            .map_err(|e| anyhow::Error::new(e).context(\"plugin code contains null bytes\"))?;\n        let call_site = CString::new(call_site)\n            .map_err(|e| anyhow::Error::new(e).context(\"call site contains null bytes\"))?;\n        py.run(&code, Some(&globals), None)\n            .map_err(anyhow::Error::from)?;\n        py.eval(&call_site, Some(&globals), None)\n            .map_err(|_| missing_fn_error)\n    }\n}\n\n/// Serializes temporary `sys.path` mutation during multi-file plugin imports.\nstatic SYS_PATH_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));\n\n/// True when `err` is a `ModuleNotFoundError` for `module_name` itself, so no\n/// plugin code has run and re-importing is side-effect free.\nfn is_module_not_found(py: Python<'_>, err: &PyErr, module_name: &str) -> bool {\n    err.is_instance_of::<PyModuleNotFoundError>(py)\n        && err\n            .value(py)\n            .getattr(\"name\")\n            .ok()","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_py_api/src/system_py.rs#L276-L312","documentation":"The call-site expression (the snippet evaluated by py.eval to fetch the plugin function) is also converted to CString, which fails on interior NUL bytes; the error is wrapped with 'call site contains null bytes'. Like the code variant, this guards against NUL-corrupted input reaching the Python interpreter.","triggerScenarios":"load_plugin_function (via execute_wal_flush_trigger / execute_schedule_trigger / execute_request_trigger) invoked with a call_site string containing '\\x00', typically when it is built from user- or config-supplied parts such as module or function names.","commonSituations":"Function/module names loaded from binary config or environment data; corrupted plugin metadata; path components containing encoded NULs.","solutions":["Sanitize the inputs used to build the call site (module name, function name): reject or strip '\\x00'.","Validate plugin metadata files are clean UTF-8 text before loading.","Check where call_site is constructed and add an assertion/log there to catch the corruption source."],"exampleFix":"# before\ncall_site = f\"{module}.{fn}()\"\n# after\ncall_site = f\"{module}.{fn}()\"\nif '\\x00' in call_site:\n    raise ValueError('call site contains NUL bytes')","handlingStrategy":"validation","validationCode":"if '\\x00' in call_site:\n    raise ValueError('call site contains NUL bytes')  # reject before load","typeGuard":null,"tryCatchPattern":"# treat like the code variant: catch the error with context 'call site contains null bytes' and reject the plugin metadata","preventionTips":["Keep plugin config/metadata files as clean UTF-8 text.","Validate module and function names against a safe pattern (e.g. ^[A-Za-z_][A-Za-z0-9_.]*$) before building the call site.","Log the raw call-site inputs when this error occurs to find the corruption source."],"tags":["rust","python","plugin","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}