{"record":{"id":"39501717dbce8fc3","repo":"chenhg5/cc-connect","slug":"url-must-start-with-http-or-https","errorCode":null,"errorMessage":"url must start with http:// or https://","messagePattern":"url must start with http:// or https://","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/hooks.go","lineNumber":121,"sourceCode":"\t\tclient:      &http.Client{},\n\t}\n}\n\nfunc validateHookConfig(h HookConfig) error {\n\tif h.Event == \"\" {\n\t\treturn fmt.Errorf(\"event is required\")\n\t}\n\tswitch HookHandlerType(h.Type) {\n\tcase HookHandlerCommand:\n\t\tif h.Command == \"\" {\n\t\t\treturn fmt.Errorf(\"command is required for type=command\")\n\t\t}\n\tcase HookHandlerHTTP:\n\t\tif h.URL == \"\" {\n\t\t\treturn fmt.Errorf(\"url is required for type=http\")\n\t\t}\n\t\tif !strings.HasPrefix(h.URL, \"http://\") && !strings.HasPrefix(h.URL, \"https://\") {\n\t\t\treturn fmt.Errorf(\"url must start with http:// or https://\")\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown handler type %q (must be command or http)\", h.Type)\n\t}\n\treturn nil\n}\n\n// Emit dispatches an event to all matching hooks.\nfunc (hm *HookManager) Emit(event HookEvent) {\n\tif hm == nil {\n\t\treturn\n\t}\n\tevent.Project = hm.project\n\tif event.Timestamp.IsZero() {\n\t\tevent.Timestamp = time.Now()\n\t}\n\n\thm.mu.RLock()","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/hooks.go#L103-L139","documentation":"For http-type hooks, validateHookConfig additionally enforces that the URL uses http:// or https://. Arbitrary schemes (file://, ftp://, custom schemes) are rejected to prevent misuse of the HTTP client.","triggerScenarios":"NewHookManager receives a hook with Type == \"http\" whose URL is non-empty but does not start with \"http://\" or \"https://\" — e.g. url = \"example.com/hook\" (missing scheme) or url = \"file:///tmp/hook\".","commonSituations":"Writing url = \"localhost:8080/hook\" without a scheme; pasting a bare domain; using a non-HTTP scheme expecting it to work; internal shorthand like \"hook://...\".","solutions":["Prefix the URL with https:// (or http:// for local/plain endpoints)","Use http://127.0.0.1:PORT for local development endpoints","If a non-HTTP sink is needed, implement it as a command-type hook instead"],"exampleFix":"// before (config.toml)\nurl = \"localhost:8080/hooks/agent\"\n// after\nurl = \"http://localhost:8080/hooks/agent\"","handlingStrategy":"validation","validationCode":"for i, h := range hooks {\n    if h.Type == \"http\" && h.URL != \"\" &&\n        !strings.HasPrefix(h.URL, \"http://\") && !strings.HasPrefix(h.URL, \"https://\") {\n        return fmt.Errorf(\"hooks[%d]: url must start with http:// or https://\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":"u, err := url.Parse(h.URL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n    return fmt.Errorf(\"hook url must be absolute http(s): %q\", h.URL)\n}","preventionTips":["Always write full URLs including the scheme in hook configs","Parse the URL with net/url when building configs programmatically","Use http://127.0.0.1 explicitly for local endpoints instead of a bare host","Lint hook URLs in CI"],"tags":["hooks","validation","url"],"backgroundTag":"invalid-url-format","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}