influxdata/influxdb · error · ExecutePluginError::PluginError
Failed to load function
Error message
Failed to load function '{function_name}' from plugin module '{module_name}': {e} What it means
Thrown when the plugin module imported successfully but `module.getattr(function_name)` fails with something other than a plain missing attribute (e.g. AttributeError whose getter raised, TypeError, or another Python exception during attribute access). A plain missing function yields a distinct 'missing function' error; this error surfaces all other getattr failures with their original cause.
Solutions
- Inspect the wrapped Python exception text — it shows why attribute access failed; fix that in the plugin file.
- Confirm the entry-point function is defined at module top level with the exact name passed to load_plugin_function: `def _trigger(...)` matching the configured name.
- Remove any custom __getattr__/module-level magic in the plugin; define the function directly.
- Simplify the plugin to a minimal `def trigger(...): pass` and reload to isolate whether the failure is in the function definition chain.
Example fix
// before (plugin my_plugin.py)
class Wrapper:
def __getattr__(self, name):
raise RuntimeError("boom")
trigger = Wrapper()
// after
def trigger(args):
... Defensive patterns
Strategy: try-catch
Validate before calling
// verify the entry point exists before triggering a load
import subprocess, sys, json
r = subprocess.run([sys.executable, "-c",
f"import {module_name}; print(hasattr({module_name}, '{fn_name}'))"],
capture_output=True, text=True, cwd=plugin_parent_dir)
if r.stdout.strip() != "True":
raise SystemExit(f"Function '{fn_name}' not found in plugin '{module_name}'") Try / catch
try {
loadPluginFunction(dir, module, fn);
} catch (e) {
if (String(e.message).includes("Failed to load function")) {
console.error(`Entry point '${fn}' inaccessible in '${module}': ${e.message}`);
} else throw e;
} Prevention
- Define the trigger function at module top level with the exact configured name.
- Avoid custom __getattr__ or descriptor magic in plugin modules.
- After edits, reload/restart so a partially executed module can't leave names unbound.
- Keep a smoke test that imports each plugin and asserts the trigger attribute exists.
When it happens
Trigger: load_plugin_function asks for a trigger function name that exists as an attribute whose access raises — e.g. the module defines `function_name` as a property/descriptor that raises, name is shadowed by an object whose __getattr__ throws, or a module-level __getattr__ hook raises instead of raising AttributeError cleanly.
Common situations: Plugin defines the trigger name but assignment itself failed silently earlier; module uses `__getattr__` lazy loading that throws; a typo'd decorator wraps the function in an object that errors on access; Python module partially executed after a caught exception left names unbound.
Related errors
- error converting the schedule time
- Failed to import plugin module
- Invalid plugin directory name
- Invalid UTF-8 in parent directory path
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/478a094a6cddea80.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_py_api/src/system_py.rs:383
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.
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,
table_filter: Option<TableId>,View on GitHub (pinned to 06200ef96b)