{"record":{"id":"13d4f04ab2fb48f3","repo":"sipeed/picoclaw","slug":"start-process-hook-w","errorCode":null,"errorMessage":"start process hook: %w","messagePattern":"start process hook: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/hook_process.go","lineNumber":130,"sourceCode":"\tif len(opts.Env) > 0 {\n\t\tcmd.Env = append(os.Environ(), opts.Env...)\n\t}\n\tstdin, err := cmd.StdinPipe()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create process hook stdin: %w\", err)\n\t}\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create process hook stdout: %w\", err)\n\t}\n\tstderr, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create process hook stderr: %w\", err)\n\t}\n\t// Route hook subprocess startup through the shared isolation entry point so\n\t// process hooks inherit the same isolation behavior as other child processes.\n\tif err := isolation.Start(cmd); err != nil {\n\t\treturn nil, fmt.Errorf(\"start process hook: %w\", err)\n\t}\n\n\tph := &ProcessHook{\n\t\tname:         name,\n\t\topts:         opts,\n\t\tcmd:          cmd,\n\t\tstdin:        stdin,\n\t\tobserveKinds: newProcessHookObserveKinds(opts.ObserveKinds),\n\t\tpending:      make(map[uint64]chan processHookRPCMessage),\n\t\tdone:         make(chan struct{}),\n\t}\n\n\tgo ph.readLoop(stdout)\n\tgo ph.readStderr(stderr)\n\tgo ph.waitLoop()\n\n\thelloCtx := ctx\n\tif helloCtx == nil {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/agent/hook_process.go#L112-L148","documentation":"Returned by NewProcessHook when isolation.Start(cmd) — the shared child-process isolation entry point that ultimately calls exec.Cmd.Start — cannot launch the hook command. This is the most common hook startup failure: the wrapped error tells you why (exec format, not found, permission, bad working dir, or sandbox denial).","triggerScenarios":"spec.Command[0] points to a binary that does not exist (exec: \"...\": executable file not found in $PATH), a file without the executable bit, a non-ELF script without a shebang, opts.Dir set to a nonexistent directory, or the isolation/sandbox layer refusing the spawn.","commonSituations":"Relative command path resolved against an unexpected cwd; forgetting chmod +x on a hook script; Windows line endings breaking a shebang; hook binary not shipped/installed on the deployment host; sandbox config (seccomp/landlock/container profile) blocking exec.","solutions":["Verify the command exists and is executable from the host process's cwd and PATH: use an absolute path in the hook config","chmod +x the hook script and ensure scripts start with a valid shebang (#!/usr/bin/env ...)","If opts.Dir is set, confirm that directory exists and is accessible","If the isolation layer is active, check its log/config for a denial and allowlist the hook binary"],"exampleFix":"# before\nhooks:\n  process:\n    my-hook:\n      command: [\"./hooks/my-hook\"]   # relative, depends on cwd\n\n# after\nhooks:\n  process:\n    my-hook:\n      command: [\"/opt/myapp/hooks/my-hook\"]   # absolute, executable","handlingStrategy":"validation","validationCode":"func validateHookCommand(spec config.ProcessHookConfig) error {\n    if len(spec.Command) == 0 {\n        return fmt.Errorf(\"hook command is required\")\n    }\n    bin := spec.Command[0]\n    path := bin\n    if !filepath.IsAbs(path) {\n        var err error\n        path, err = exec.LookPath(bin)\n        if err != nil {\n            return fmt.Errorf(\"hook binary %q not found in PATH: %w\", bin, err)\n        }\n    }\n    info, err := os.Stat(path)\n    if err != nil {\n        return fmt.Errorf(\"hook binary %q inaccessible: %w\", path, err)\n    }\n    if info.Mode()&0111 == 0 {\n        return fmt.Errorf(\"hook binary %q is not executable\", path)\n    }\n    if spec.Dir != \"\" {\n        if _, err := os.Stat(spec.Dir); err != nil {\n            return fmt.Errorf(\"hook dir %q invalid: %w\", spec.Dir, err)\n        }\n    }\n    return nil\n}","typeGuard":"func isHookStartError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"start process hook:\")\n}","tryCatchPattern":"ph, err := NewProcessHook(ctx, name, opts)\nif err != nil {\n    if isHookStartError(err) {\n        // surface exec.ErrNotFound / permission errors with the binary path\n        return fmt.Errorf(\"failed to launch hook %q (%s): %w\", name, opts.Command[0], err)\n    }\n    return err\n}","preventionTips":["Use absolute paths for hook commands in deployed configs","chmod +x hook scripts and verify shebangs in CI","Smoke-test each hook binary from the same cwd/user the agent runs as"],"tags":["process","exec","hooks","isolation","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}