influxdata/influxdb · error · anyhow::Error
Invalid UTF-8 in parent directory path
Error message
Invalid UTF-8 in parent directory path
What it means
Thrown by load_function_from_module when the parent directory of the plugin root (the directory that must be prepended to sys.path so the plugin module is importable) is not valid UTF-8. Python's sys.path entries must be strings, so a non-UTF-8 OsStr cannot be converted with to_str().
Solutions
- Rename the offending ancestor directory of the plugin path so the entire path is valid UTF-8.
- Check the filesystem encoding/locale the process runs under (`locale`); run with a UTF-8 locale (LC_ALL=C.UTF-8) so paths encode cleanly.
- Validate the plugin directory path with `Path::to_str().is_some()` before calling the API and fail fast with a clear message.
- Avoid symlinking plugin dirs through paths with exotic names; place plugins under a simple ASCII path like /var/lib/influxdb3/plugins.
Defensive patterns
Strategy: validation
Validate before calling
const path = process.env.INFLUXDB3_PLUGIN_DIR ?? "";
const encoder = new TextEncoder();
// Node keeps UTF-8 internally; validate round-trip of raw bytes from the FS before use
if (!path || Buffer.compare(Buffer.from(path, "utf8"), encoder.encode(path)) !== 0) {
throw new Error(`Plugin dir path '${path}' is not valid UTF-8`);
} Prevention
- Run the server under a UTF-8 locale (LC_ALL=C.UTF-8).
- Keep the whole plugin path (including ancestors) ASCII/UTF-8; avoid renamed dirs with exotic bytes.
- Validate with Rust's Path::to_str() before calling the API and surface a clear config error.
When it happens
Trigger: load_plugin_function invoked with a plugin_directory whose PARENT path component contains non-UTF-8 bytes (e.g. a directory name with raw bytes or invalid encoding), preventing `parent_dir.to_str()` from succeeding.
Common situations: InfluxDB installed or plugins stored under a path containing characters produced by a non-UTF-8 filesystem encoding or pasted control characters; running under a locale like LC_ALL=C/POSIX where user-created paths use surrogate bytes; symlinks or mounts with unusual names.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid plugin directory name
- Error converting CSV output to UTF-8
- Error converting JSON output to UTF-8
- error converting the schedule time
- error writing wal file
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/b9034d00bf60b869.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_py_api/src/system_py.rs:340
py: Python<'py>,
plugin_root: &Path,
function_name: &str,
missing_fn_error: ExecutePluginError,
) -> Result<Bound<'py, PyAny>, ExecutePluginError> {
let parent_dir = plugin_root
.parent()
.ok_or_else(|| anyhow!("Plugin root has no parent directory"))?;
let module_name = plugin_root
.file_name()
.and_then(|n| n.to_str())
.ok_or_else(|| anyhow!("Invalid plugin directory name"))?;
let sys = py.import("sys").map_err(anyhow::Error::from)?;
let sys_path = sys.getattr("path").map_err(anyhow::Error::from)?;
let parent_dir_str = parent_dir
.to_str()
.ok_or_else(|| anyhow!("Invalid UTF-8 in parent directory path"))?;
// Acquire while attached to the Python runtime; `lock_py_attached` detaches
// internally if the lock is contended, avoiding a GIL/lock deadlock.
let _sys_path_guard = SYS_PATH_LOCK.lock_py_attached(py);
// Add parent directory to sys.path
sys_path
.call_method1("insert", (0, parent_dir_str))
.map_err(anyhow::Error::from)?;
// A plugin dir added after FileFinder cached the parent is invisible until
// import caches are invalidated; retry once.
let import_result = match py.import(module_name) {
Err(e) if is_module_not_found(py, &e, module_name) => {
let _ = py
.import("importlib")
.and_then(|m| m.call_method0("invalidate_caches"));
py.import(module_name)View on GitHub (pinned to 06200ef96b)