{"record":{"id":"200b8f057e73d1ce","repo":"chenhg5/cc-connect","slug":"either-prompt-or-exec-is-required-200b8f","errorCode":null,"errorMessage":"either prompt or exec is required","messagePattern":"either prompt or exec is required","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"core/webhook.go","lineNumber":108,"sourceCode":"\t}\n\n\tif !ws.authenticate(r) {\n\t\thttp.Error(w, \"unauthorized\", http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\tvar req WebhookRequest\n\tif err := json.NewDecoder(r.Body).Decode(&req); err != nil {\n\t\thttp.Error(w, \"invalid JSON: \"+err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif req.SessionKey == \"\" {\n\t\thttp.Error(w, \"session_key is required\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tif req.Prompt == \"\" && req.Exec == \"\" {\n\t\thttp.Error(w, \"either prompt or exec is required\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tif req.Prompt != \"\" && req.Exec != \"\" {\n\t\thttp.Error(w, \"prompt and exec are mutually exclusive\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tengine, err := ws.resolveEngine(req.Project)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\teventName := req.Event\n\tif eventName == \"\" {\n\t\teventName = \"webhook\"\n\t}\n","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/webhook.go#L90-L126","documentation":"handleHook validation: the request carries neither prompt nor exec, so there is nothing to run. Sentinel guard returning HTTP 400; exactly one of the two fields must be non-empty (both set is rejected separately).","triggerScenarios":"Posting JSON with only session_key (and optional project/event) but no prompt or exec field; both fields present but empty strings.","commonSituations":"Template or automation building the payload drops the action field when a variable is empty; sending an event-only request that the API doesn't support.","solutions":["Add a non-empty prompt (natural-language instruction) or exec (command) field.","If the action value comes from a variable, check it isn't empty/whitespace before sending.","If you only intended a ping/health check, don't use the hook endpoint for that."],"exampleFix":"// before\n{\"session_key\": \"s1\"}\n// after\n{\"session_key\": \"s1\", \"exec\": \"go test ./...\"}","handlingStrategy":"validation","validationCode":"func checkWebhookReq(r WebhookRequest) error {\n    if r.Prompt == \"\" && r.Exec == \"\" { return errors.New(\"either prompt or exec is required\") }\n    return nil\n}","typeGuard":"func hasAction(p map[string]any) bool {\n    pr, _ := p[\"prompt\"].(string); ex, _ := p[\"exec\"].(string)\n    return pr != \"\" || ex != \"\"\n}","tryCatchPattern":"resp, err := http.Post(url, \"application/json\", bytes.NewReader(payload))\nif err == nil && resp.StatusCode == 400 {\n    b, _ := io.ReadAll(resp.Body)\n    if strings.Contains(string(b), \"either prompt or exec\") {\n        return errors.New(\"payload had no action: set prompt or exec\")\n    }\n    return fmt.Errorf(\"webhook rejected: %s\", b)\n}","preventionTips":["Check template variables for empty values before rendering payloads","Treat prompt/exec as the required core of every hook request","Add a builder function that refuses to emit payloads without an action","Don't repurpose the hook endpoint for pings or health checks"],"tags":["webhook","validation","required-field","http-400"],"backgroundTag":"missing-required-argument","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}