influxdata/influxdb · error · anyhow::Error
call site contains null bytes
Error message
call site contains null bytes
What it means
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.
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.
Example fix
# before
call_site = f"{module}.{fn}()"
# after
call_site = f"{module}.{fn}()"
if '\x00' in call_site:
raise ValueError('call site contains NUL bytes') Defensive patterns
Strategy: validation
Validate before calling
if '\x00' in call_site:
raise ValueError('call site contains NUL bytes') # reject before load Try / catch
# treat like the code variant: catch the error with context 'call site contains null bytes' and reject the plugin metadata
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Function/module names loaded from binary config or environment data; corrupted plugin metadata; path components containing encoded NULs.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- plugin code contains null bytes
- invalid database name
- Plugin root has no parent directory
- {0}
- All `DataPoints` must have at least one field. Builder…
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/8604eecee8386cfb.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_py_api/src/system_py.rs:294
/// retrieves the function.
fn load_plugin_function<'py>(
py: Python<'py>,
code: &str,
plugin_root: Option<&Path>,
call_site: &str,
missing_fn_error: ExecutePluginError,
) -> Result<Bound<'py, PyAny>, ExecutePluginError> {
if let Some(root_path) = plugin_root {
load_function_from_module(py, root_path, call_site, missing_fn_error)
} else {
// Create isolated globals for this plugin execution. Without this, single-file
// plugins would share __main__'s namespace and could overwrite each other's
// function definitions during concurrent execution.
let globals = PyDict::new(py);
let code = CString::new(code)
.map_err(|e| anyhow::Error::new(e).context("plugin code contains null bytes"))?;
let call_site = CString::new(call_site)
.map_err(|e| anyhow::Error::new(e).context("call site contains null bytes"))?;
py.run(&code, Some(&globals), None)
.map_err(anyhow::Error::from)?;
py.eval(&call_site, Some(&globals), None)
.map_err(|_| missing_fn_error)
}
}
/// Serializes temporary `sys.path` mutation during multi-file plugin imports.
static SYS_PATH_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// True when `err` is a `ModuleNotFoundError` for `module_name` itself, so no
/// plugin code has run and re-importing is side-effect free.
fn is_module_not_found(py: Python<'_>, err: &PyErr, module_name: &str) -> bool {
err.is_instance_of::<PyModuleNotFoundError>(py)
&& err
.value(py)
.getattr("name")
.ok()View on GitHub (pinned to 06200ef96b)