influxdata/influxdb · error
plugin code contains null bytes
Error message
plugin code contains null bytes
What it means
Single-file plugins (no plugin_root) are executed by passing their source to py.run after converting it with CString::new, and C strings cannot contain NUL bytes. If the stored plugin code contains a single '\0', CString::new fails and the error is wrapped with context 'plugin code contains null bytes'. In practice this means the uploaded 'source' is not text at all — it is binary, corrupt, or wrongly encoded.
Source
Thrown at influxdb3_py_api/src/system_py.rs:296
/// For multi-file plugins (when `plugin_root` is `Some`), imports the module and retrieves
/// the function. For single-file plugins, executes the code in an isolated namespace and
/// 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)View on GitHub (pinned to d28e26e048)
Solutions
- Re-save the plugin file as UTF-8 (no BOM) and re-upload
- Verify before upload: the file contains no NUL bytes (check b'\x00' in data)
- If you meant to ship compiled code, don't — the engine executes plain .py source; multi-file plugin directories are the packaging mechanism
Example fix
# before: plugin.py saved as UTF-16 / binary -> 'plugin code contains null bytes'
# after: verify plain UTF-8 text before upload
src = open("plugin.py", "rb").read()
assert b"\x00" not in src, "not valid UTF-8 text"
upload(plugin="plugin.py") Defensive patterns
Strategy: validation
Validate before calling
src = open("plugin.py", "rb").read()
assert b"\x00" not in src, "plugin file contains NUL bytes — re-save as UTF-8 text"
src.decode("utf-8") # must succeed
# only then upload Prevention
- Save plugin files as UTF-8 without BOM; avoid UTF-16 encodings from editors on Windows
- Upload plain .py source, never .pyc/zip/binary artifacts
- Add an encoding check to your plugin upload pipeline
When it happens
Trigger: Uploading a compiled/binary artifact (e.g. a .pyc) or a file saved as UTF-16 (whose byte stream contains NULs) as single-file plugin code; a truncated or binary-corrupted transfer leaving stray NUL bytes in the .py file.
Common situations: Editor or pipeline re-saving the plugin with UTF-16 encoding; build steps that publish compiled artifacts; copy-paste through tools that mangle encoding; accidental upload of a zip/gz file.
Related errors
- Failed to import plugin module '{}': {} Hint: Check for synt
- Measurement name cannot contain spaces
- {key_type} key cannot be empty
- {key_type} key '{key}' cannot contain spaces
- {key_type} key '{key}' cannot contain commas
AI-assisted analysis of influxdata/influxdb@d28e26e048 (2026-08-16).
Data as JSON: /api/errors/6510aef825152816.
Report an issue: GitHub.