influxdata/influxdb · error · ExecutePluginError
Failed to load function '{}' from plugin module '{}': {}
Error message
Failed to load function '{}' from plugin module '{}': {} What it means
The InfluxDB 3 Python plugin host imports each plugin module and resolves the configured entry-point function (e.g. process_request for request plugins) via getattr. A plain AttributeError is mapped to a dedicated MissingProcessRequestFunction error; this PluginError is only produced when the attribute lookup fails with some other exception. The message shows the requested function name, module name, and the underlying Python exception, which is the real cause.
Source
Thrown at influxdb3_py_api/src/system_py.rs:387
let _ = sys_path.call_method1("pop", (0,));
// Any import failure is the real load error and must not be masked.
let module = import_result.map_err(|e| {
ExecutePluginError::PluginError(anyhow!(
"Failed to import plugin module '{}': {}\n\
Hint: Check for syntax errors or missing dependencies in Python files.",
module_name,
e
))
})?;
module.getattr(function_name).map_err(|e| {
// Only a missing attribute on the imported module means the entry-point
// function is absent; surface anything else as the real cause.
if e.is_instance_of::<PyAttributeError>(py) {
missing_fn_error
} else {
ExecutePluginError::PluginError(anyhow!(
"Failed to load function '{}' from plugin module '{}': {}",
function_name,
module_name,
e
))
}
})
}
/// Execute a WAL flush trigger plugin.
#[allow(clippy::too_many_arguments)]
pub fn execute_wal_flush_trigger(
code: &str,
wal_data: &[WalFlushElement],
schema: Arc<DatabaseSchema>,
query_endpoint: Arc<dyn QueryEndpoint>,
write_endpoint: Arc<dyn WriteEndpoint>,
logger: PluginLogger,View on GitHub (pinned to d28e26e048)
Solutions
- Read the trailing Python exception in the message - it names the actual failing code in the plugin module
- Reproduce outside the server: run python -c "import my_plugin; my_plugin.process_request" from the plugin directory
- Make the entry point a plain module-level def and remove module-level __getattr__/descriptors that intercept the lookup
- Delete stale __pycache__ directories under the plugin root and reload the plugin
Example fix
# before (plugin.py)
_ENTRY_POINTS = {}
def __getattr__(name):
if name not in _ENTRY_POINTS:
raise RuntimeError(f'unknown entry point: {name}') # becomes PluginError
return _ENTRY_POINTS[name]
# after
def process_request(influxdb, query_params, request_params, body, args):
...
Defensive patterns
Strategy: validation
Validate before calling
# preflight the plugin before deploying it
import importlib
mod = importlib.import_module('my_plugin')
try:
fn = getattr(mod, 'process_request')
except AttributeError:
raise SystemExit('entry point missing')
except Exception as e:
raise SystemExit(f'entry-point lookup itself raised: {e}') # this is the PluginError path
assert callable(fn)
Type guard
def entry_point_ok(module_name: str, fn_name: str = 'process_request') -> bool:
try:
return callable(getattr(importlib.import_module(module_name), fn_name))
except Exception:
return False
Try / catch
// Rust: distinguish load failure from missing function
match execute_plugin(...) {
Err(ExecutePluginError::PluginError(e)) => log::error!("plugin load failed: {e:#}"),
Err(ExecutePluginError::MissingProcessRequestFunction) => log::error!("process_request not defined"),
Ok(v) => { /* ... */ }
}
Prevention
- Keep plugin entry points as plain module-level def functions
- Add a CI step that imports each plugin and asserts callable(getattr(mod, 'process_request'))
- Avoid module-level __getattr__ and lazy-attribute machinery in plugin modules
- Clear __pycache__ under the plugin root after upgrading the server's Python
When it happens
Trigger: The plugin module defines a module-level __getattr__ (PEP 562) that raises for the entry-point name; the entry point is a descriptor/property whose access raises; or a package __init__ was left partially initialized after a swallowed import error, so getattr(process_request) raises something other than AttributeError.
Common situations: Plugins using metaprogramming (lazy imports, generated attributes), plugin code written against a newer/older SDK whose module shape changed, or stale __pycache__ from a different Python version causing attribute access to fail.
Related errors
- Python function call failed: {}
- Unsupported return type from Python function
- timestamp, {}, out of range for precision: {:?}
- cannot fit duration into u64
- metric should be in progress
AI-assisted analysis of influxdata/influxdb@d28e26e048 (2026-08-16).
Data as JSON: /api/errors/3346010afe1c8410.
Report an issue: GitHub.