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

  1. Add a handler in cfg.Handlers keyed exactly by the definition's Name reported in the error message.
  2. Fix key/name mismatches by generating Handlers keys from def.Name programmatically.
  3. 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

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


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/bcf4af323bd9c9ae. Report an issue: GitHub.