JuliusBrussee/caveman · error
native hook payload too large
Error message
native hook payload too large
What it means
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.
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.
Example fix
// before (hook config) "command": "cat "$TOOL_OUTPUT" | caveman-proxy native-hook" // after "command": "head -c 60000 "$TOOL_OUTPUT" | caveman-proxy native-hook"
Defensive patterns
Strategy: validation
Validate before calling
// before piping to the native hook bridge
const maxPayload = 64 * 1024 // match nativeHookMaxPayloadBytes
if stat, err := os.Stdin.Stat(); err == nil && stat.Size() > int64(maxPayload) {
return errors.New("hook input exceeds payload limit; truncate first")
} Try / catch
payload, err := readNativeHookPayload(r)
if err != nil && err.Error() == "native hook payload too large" {
log.Printf("hook payload rejected; trim hook output and retry")
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: A PostToolUse/Stop hook whose JSON includes massive transcript or tool-result content; users piping debug dumps into caveman-proxy's native hook mode.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- compat upstream name
- header cannot be forwarded
- invalid Decision Ledger response
- hooks. must be an array; refusing to overwrite it
- hooks must be a JSON object; refusing to overwrite it
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/d666a281fba08a05.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/cmd/caveman-proxy/main.go:117
return
}
home = filepath.Join(userHome, ".caveman")
}
raw, err := readNativeHookPayload(os.Stdin)
if err != nil || len(raw) > nativeHookMaxPayloadBytes {
return
}
_ = nativehook.Run(context.Background(), home, agent, adapter, raw, os.Stdout, os.Stderr)
}
func readNativeHookPayload(r io.Reader) ([]byte, error) {
raw := make([]byte, 0, 4096)
buf := make([]byte, 16*1024)
for {
n, err := r.Read(buf)
if n > 0 {
if len(raw)+n > nativeHookMaxPayloadBytes {
return nil, fmt.Errorf("native hook payload too large")
}
raw = append(raw, buf[:n]...)
if json.Valid(raw) {
return raw, nil
}
}
if err != nil {
if err == io.EOF {
return raw, nil
}
return nil, err
}
}
}
func runNativeWhy(logger *slog.Logger, args []string) {
decisionID := argFlag(args, "--decision", "")
if decisionID == "" && len(args) == 1 && !strings.HasPrefix(args[0], "-") {View on GitHub (pinned to 3ee70a1026)