vxcontrol/pentagi · error
handler for function %s not found
Error message
handler for function %s not found
What it means
After the length check, GetCustomExecutor iterates every FunctionDefinition in cfg.Definitions and requires a handler keyed by def.Name in cfg.Handlers. If a definition lacks a handler, the executor cannot dispatch calls to that function, so it refuses to build the custom executor with this named error.
Source
Thrown at backend/pkg/tools/tools.go:778
}
// TODO: here better to get flow containers list and purge all of them
if err := fte.docker.RemoveContainer(ctx, fte.primaryLID, fte.primaryID); err != nil {
containerName := PrimaryTerminalName(fte.cfg.TenantPrefix(), fte.flowID)
return fmt.Errorf("failed to purge container '%s': %w", containerName, err)
}
return nil
}
func (fte *flowToolsExecutor) GetCustomExecutor(cfg CustomExecutorConfig) (ContextToolsExecutor, error) {
if len(cfg.Definitions) != len(cfg.Handlers) {
return nil, fmt.Errorf("definitions and handlers must have the same length")
}
for _, def := range cfg.Definitions {
if _, ok := cfg.Handlers[def.Name]; !ok {
return nil, fmt.Errorf("handler for function %s not found", def.Name)
}
}
for _, builtin := range cfg.Builtin {
if def, ok := fte.definitions[builtin]; !ok {
return nil, fmt.Errorf("builtin function %s not found", builtin)
} else {
cfg.Definitions = append(cfg.Definitions, def)
cfg.Handlers[builtin] = fte.handlers[builtin]
}
}
barriers := make(map[string]struct{})
for _, barrier := range cfg.Barriers {
if _, ok := fte.handlers[barrier]; !ok {
return nil, fmt.Errorf("barrier function %s not found", barrier)
}
barriers[barrier] = struct{}{}View on GitHub (pinned to ea665308ba)
Solutions
- Add a handler in cfg.Handlers keyed exactly by the definition's Name reported in the error message.
- Fix key/name mismatches by generating Handlers keys from def.Name programmatically.
- Add a unit test that builds the CustomExecutorConfig and asserts GetCustomExecutor returns no error.
Example fix
// before
Definitions: []tools.FunctionDefinition{{Name: "port_scan"}},
Handlers: map[string]tools.Handler{"scan_port": hScan},
// after
Definitions: []tools.FunctionDefinition{{Name: "port_scan"}},
Handlers: map[string]tools.Handler{"port_scan": hScan}, Defensive patterns
Strategy: validation
Validate before calling
for _, def := range cfg.Definitions {
if _, ok := cfg.Handlers[def.Name]; !ok {
return fmt.Errorf("definition %q has no handler", def.Name)
}
} Type guard
func allHandlersPresent(cfg tools.CustomExecutorConfig) bool {
for _, d := range cfg.Definitions {
if _, ok := cfg.Handlers[d.Name]; !ok {
return false
}
}
return true
} Try / catch
executor, err := flowTools.GetCustomExecutor(cfg)
if err != nil && strings.Contains(err.Error(), "handler for function") {
// fix the tool registration table named in the error before retrying
return fmt.Errorf("tool registration bug: %w", err)
} Prevention
- Always key the Handlers map from def.Name, never by hand-typed strings.
- Keep each tool's definition and handler adjacent in code (same struct literal) so they change together.
- Cover every registered tool with a build-time or test-time check that handlers resolve.
When it happens
Trigger: Calling GetCustomExecutor with a definition whose Name has no entry in cfg.Handlers — typically when Definitions and Handlers are maintained by hand and a handler key is misspelled relative to the definition name, or a handler was deleted while the definition remained.
Common situations: Typo mismatch between def.Name ("web_search") and handler key ("websearch"); refactoring a tool name in the definition but not the handler map; conditionally registering definitions while handlers are built unconditionally (or vice versa).
Related errors
- definitions and handlers must have the same length
- builtin function %s not found
- invalid provider config: %w
- unsupported agent type: %s
- test case has no prompt or messages
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/bcf4af323bd9c9ae.
Report an issue: GitHub.