{"record":{"id":"342ad1101ae92f86","repo":"sipeed/picoclaw","slug":"mount-builtin-hook-q-w","errorCode":null,"errorMessage":"mount builtin hook %q: %w","messagePattern":"mount builtin hook %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/hook_mount.go","lineNumber":160,"sourceCode":"\tbuiltinNames := enabledBuiltinHookNames(al.cfg.Hooks.Builtins)\n\tfor _, name := range builtinNames {\n\t\tspec := al.cfg.Hooks.Builtins[name]\n\t\tfactory, ok := lookupBuiltinHook(name)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"builtin hook %q is not registered\", name)\n\t\t}\n\n\t\thook, factoryErr := factory(ctx, spec)\n\t\tif factoryErr != nil {\n\t\t\treturn fmt.Errorf(\"build builtin hook %q: %w\", name, factoryErr)\n\t\t}\n\t\tif err := al.MountHook(HookRegistration{\n\t\t\tName:     name,\n\t\t\tPriority: spec.Priority,\n\t\t\tSource:   HookSourceInProcess,\n\t\t\tHook:     hook,\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"mount builtin hook %q: %w\", name, err)\n\t\t}\n\t\tmounted = append(mounted, name)\n\t}\n\n\tprocessNames := enabledProcessHookNames(al.cfg.Hooks.Processes)\n\tfor _, name := range processNames {\n\t\tspec := al.cfg.Hooks.Processes[name]\n\t\topts, buildErr := processHookOptionsFromConfig(spec)\n\t\tif buildErr != nil {\n\t\t\treturn fmt.Errorf(\"configure process hook %q: %w\", name, buildErr)\n\t\t}\n\n\t\tprocessHook, buildErr := NewProcessHook(ctx, name, opts)\n\t\tif buildErr != nil {\n\t\t\treturn fmt.Errorf(\"start process hook %q: %w\", name, buildErr)\n\t\t}\n\t\tif err := al.MountHook(HookRegistration{\n\t\t\tName:     name,","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/agent/hook_mount.go#L142-L178","documentation":"After a builtin hook builds, it is attached via AgentLoop.MountHook -> HookManager.Mount, which only fails when the hook manager is nil, the name is empty, or the hook value is nil (pkg/agent/hooks.go:274). In this config-driven path the name comes from the config map key and the hook was just built non-nil, so the realistic cause is al.hooks being uninitialized — a hand-constructed AgentLoop that skipped the normal constructor wiring.","triggerScenarios":"hooks.enabled=true with builtins enabled on an AgentLoop built without a HookManager (custom construction in tests or forks bypassing NewAgentLoop), making MountHook return 'hook manager is not initialized' which gets wrapped here.","commonSituations":"Unit tests assembling AgentLoop structs literally; forks that build the loop with reflection or partial constructors; disabling subsystems during construction but leaving hooks on in config.","solutions":["Construct the AgentLoop through the standard constructor so the hook manager is created","If hooks are not wanted, set hooks.enabled=false rather than building a hook-less loop with hooks on in config","In tests, either use the full constructor or disable hooks in the test config","Check the wrapped message — 'hook manager is not initialized' confirms the wiring diagnosis"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if cfg.Hooks.Enabled && len(cfg.Hooks.Builtins) > 0 {\n    if al.HooksManager() == nil { // adapt to your embedding's accessor\n        return fmt.Errorf(\"hooks enabled in config but AgentLoop has no hook manager; use the standard constructor\")\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := al.MountHook(reg); err != nil {\n    if strings.Contains(err.Error(), \"hook manager is not initialized\") {\n        // wiring bug: rebuild the loop with the standard constructor; not a runtime-transient error\n        return fmt.Errorf(\"loop constructed without hook manager: %w\", err)\n    }\n    return err\n}","preventionTips":["Never hand-construct AgentLoop structs; use the provided constructor which wires the HookManager","In tests, disable hooks in config instead of stripping subsystems from the struct","Treat any MountHook failure as a programming error — surface it, do not swallow it"],"tags":["go","picoclaw","hooks","wiring","custom-embedding"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}