sipeed/picoclaw · error

mount process hook %q: %w

Error message

mount process hook %q: %w

What it means

Identical failure surface to the builtin-hook mount error, but for process hooks: after NewProcessHook succeeds, AgentLoop.MountHook -> HookManager.Mount failed (nil hook manager, empty name, or nil hook). On this path the just-started subprocess is Closed before returning, so no orphan process leaks. Realistic cause is an AgentLoop built without a HookManager.

Source

Thrown at pkg/agent/hook_mount.go:184

	for _, name := range processNames {
		spec := al.cfg.Hooks.Processes[name]
		opts, buildErr := processHookOptionsFromConfig(spec)
		if buildErr != nil {
			return fmt.Errorf("configure process hook %q: %w", name, buildErr)
		}

		processHook, buildErr := NewProcessHook(ctx, name, opts)
		if buildErr != nil {
			return fmt.Errorf("start process hook %q: %w", name, buildErr)
		}
		if err := al.MountHook(HookRegistration{
			Name:     name,
			Priority: spec.Priority,
			Source:   HookSourceProcess,
			Hook:     processHook,
		}); err != nil {
			_ = processHook.Close()
			return fmt.Errorf("mount process hook %q: %w", name, err)
		}
		mounted = append(mounted, name)
	}

	return nil
}

func enabledBuiltinHookNames(specs map[string]config.BuiltinHookConfig) []string {
	if len(specs) == 0 {
		return nil
	}

	names := make([]string, 0, len(specs))
	for name, spec := range specs {
		if spec.Enabled {
			names = append(names, name)
		}
	}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Build the AgentLoop with the standard constructor so a HookManager exists
  2. Set hooks.enabled=false in configs used with hook-less loops
  3. In tests, use the full constructor or trim the config's hooks section
  4. Check the wrapped message ('hook manager is not initialized') to confirm wiring is the problem
Defensive patterns

Strategy: try-catch

Try / catch

if err := al.MountHook(reg); err != nil {
    if strings.Contains(err.Error(), "hook manager is not initialized") {
        // process already Closed by the caller; rebuild loop wiring, do not retry
        return fmt.Errorf("loop constructed without hook manager: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: hooks.processes.<name> starts fine but MountHook fails because al.hooks is nil — custom/hand-built AgentLoop (tests, forks) with hooks.enabled=true and a process hook enabled in config.

Common situations: Test harnesses constructing AgentLoop structs directly; forks with partial construction; hook manager deliberately omitted while hooks remain enabled in config.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/800e6cc29dbd5e89. Report an issue: GitHub.