{"record":{"id":"6510aef825152816","repo":"influxdata/influxdb","slug":"plugin-code-contains-null-bytes","errorCode":null,"errorMessage":"plugin code contains null bytes","messagePattern":"plugin code contains null bytes","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"influxdb3_py_api/src/system_py.rs","lineNumber":292,"sourceCode":"/// For multi-file plugins (when `plugin_root` is `Some`), imports the module and retrieves\n/// the function. For single-file plugins, executes the code in an isolated namespace and\n/// 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)","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_py_api/src/system_py.rs#L274-L310","documentation":"load_plugin_function converts plugin source code to a CString for py.run(); CString::new fails if the string contains interior NUL bytes, and the error is wrapped with 'plugin code contains null bytes'. Embedded NULs would truncate the Python source, so they are rejected outright.","triggerScenarios":"Calling load_plugin_function (directly or via execute_wal_flush_trigger / execute_schedule_trigger / execute_request_trigger) with plugin code read from a binary file, a corrupt download, or a string that accidentally includes '\\x00'.","commonSituations":"Pointing the plugin loader at a compiled .pyc or binary file instead of source; file corruption during transfer; building code strings via concatenation that introduces NUL bytes.","solutions":["Verify the plugin file is valid UTF-8 Python source (file command / reading as text) and not a binary or .pyc.","Strip or reject NUL bytes before loading: if '\\x00' in code: raise/sanitize.","Re-download or re-deploy the plugin from a trusted source to rule out corruption."],"exampleFix":"# before\ncode = open(path, 'rb').read()\n# after\ncode = open(path, 'r', encoding='utf-8').read()\nassert '\\x00' not in code, 'plugin source contains NUL bytes'","handlingStrategy":"validation","validationCode":"if '\\x00' in code:\n    raise ValueError('plugin source contains NUL bytes')  # reject before load","typeGuard":null,"tryCatchPattern":"# caller-side\ncatch the anyhow error whose context is 'plugin code contains null bytes' and skip/redeploy the plugin","preventionTips":["Distribute plugins as plain UTF-8 .py source, never .pyc or binary.","Verify plugin files after deployment (checksum or encoding check).","Read plugin files in text mode so encoding issues surface early."],"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"}