{"record":{"id":"d666a281fba08a05","repo":"JuliusBrussee/caveman","slug":"native-hook-payload-too-large","errorCode":null,"errorMessage":"native hook payload too large","messagePattern":"native hook payload too large","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/cmd/caveman-proxy/main.go","lineNumber":117,"sourceCode":"\t\t\treturn\n\t\t}\n\t\thome = filepath.Join(userHome, \".caveman\")\n\t}\n\traw, err := readNativeHookPayload(os.Stdin)\n\tif err != nil || len(raw) > nativeHookMaxPayloadBytes {\n\t\treturn\n\t}\n\t_ = nativehook.Run(context.Background(), home, agent, adapter, raw, os.Stdout, os.Stderr)\n}\n\nfunc readNativeHookPayload(r io.Reader) ([]byte, error) {\n\traw := make([]byte, 0, 4096)\n\tbuf := make([]byte, 16*1024)\n\tfor {\n\t\tn, err := r.Read(buf)\n\t\tif n > 0 {\n\t\t\tif len(raw)+n > nativeHookMaxPayloadBytes {\n\t\t\t\treturn nil, fmt.Errorf(\"native hook payload too large\")\n\t\t\t}\n\t\t\traw = append(raw, buf[:n]...)\n\t\t\tif json.Valid(raw) {\n\t\t\t\treturn raw, nil\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn raw, nil\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t}\n}\n\nfunc runNativeWhy(logger *slog.Logger, args []string) {\n\tdecisionID := argFlag(args, \"--decision\", \"\")\n\tif decisionID == \"\" && len(args) == 1 && !strings.HasPrefix(args[0], \"-\") {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/cmd/caveman-proxy/main.go#L99-L135","documentation":"readNativeHookPayload streams stdin in 16 KiB chunks and enforces nativeHookMaxPayloadBytes as a hard cap on the total JSON payload. When accumulated bytes would exceed the cap, it fails fast with \"native hook payload too large\". This protects the proxy from unbounded stdin input from Claude Code native hook events.","triggerScenarios":"The native hook bridge (runNativeHookBridge) receives a hook payload larger than nativeHookMaxPayloadBytes — e.g. a hook emitting huge tool output or a misconfigured hook piping an entire file into stdin.","commonSituations":"A PostToolUse/Stop hook whose JSON includes massive transcript or tool-result content; users piping debug dumps into caveman-proxy's native hook mode.","solutions":["Reduce the hook payload size (trim tool output, disable verbose fields in hook config).","Check nativeHookMaxPayloadBytes and, if legitimately needed, raise the limit via configuration.","Inspect the hook command in the Claude Code settings for accidental file redirection into stdin.","Log/truncate payload content upstream before invoking the proxy hook bridge."],"exampleFix":"// before (hook config)\n\"command\": \"cat \"$TOOL_OUTPUT\" | caveman-proxy native-hook\"\n// after\n\"command\": \"head -c 60000 \"$TOOL_OUTPUT\" | caveman-proxy native-hook\"","handlingStrategy":"validation","validationCode":"// before piping to the native hook bridge\nconst maxPayload = 64 * 1024 // match nativeHookMaxPayloadBytes\nif stat, err := os.Stdin.Stat(); err == nil && stat.Size() > int64(maxPayload) {\n    return errors.New(\"hook input exceeds payload limit; truncate first\")\n}","typeGuard":null,"tryCatchPattern":"payload, err := readNativeHookPayload(r)\nif err != nil && err.Error() == \"native hook payload too large\" {\n    log.Printf(\"hook payload rejected; trim hook output and retry\")\n}","preventionTips":["Trim tool output in hook configs before it reaches the proxy.","Never redirect whole files into the native hook stdin.","Know nativeHookMaxPayloadBytes and pre-truncate payloads accordingly."],"tags":["payload-size","proxy","hooks","validation"],"backgroundTag":"payload-too-large","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}