micro/go-micro · error
push callback scheme %q not allowed (want http or https)
Error message
push callback scheme %q not allowed (want http or https)
What it means
defaultPushURLPolicy is the SSRF guard applied to push-notification callback URLs before the library uses them. It throws this error when the callback URL's scheme is not http or https (e.g. file:, gopher:, ftp:), because non-HTTP schemes can be abused for local file or protocol attacks. The URL must be changed before a push config can be registered.
Source
Thrown at gateway/a2a/pushsecurity.go:36
//
// The default policy allows only http/https callbacks whose host does not
// resolve to a loopback, private, link-local, or unspecified address, and the
// guarded HTTP client re-checks the *resolved* IP at dial time so a hostname
// that passes validation cannot be rebound to an internal address before the
// connection is made. Operators who need to reach a trusted in-cluster
// receiver set Options.AllowPushURL to take over the policy.
// pushLookupIP resolves a host to IPs; overridable in tests.
var pushLookupIP = net.LookupIP
// defaultPushURLPolicy is the SSRF-safe policy applied when no AllowPushURL is
// configured. It rejects non-http(s) schemes and hosts that resolve to a
// loopback, private, link-local, multicast, or unspecified address.
func defaultPushURLPolicy(u *url.URL) error {
switch u.Scheme {
case "http", "https":
default:
return fmt.Errorf("push callback scheme %q not allowed (want http or https)", u.Scheme)
}
host := u.Hostname()
if host == "" {
return fmt.Errorf("push callback url has no host")
}
ips, err := resolvePushHost(host)
if err != nil {
return fmt.Errorf("push callback host %q: %w", host, err)
}
if len(ips) == 0 {
return fmt.Errorf("push callback host %q did not resolve", host)
}
for _, ip := range ips {
if blockedPushIP(ip) {
return fmt.Errorf("push callback host %q resolves to a blocked address %s", host, ip)
}
}
return nilView on GitHub (pinned to 24529f1404)
Solutions
- Ensure the callback URL starts with http:// or https:// (prefer https in production).
- Validate/sanitize user-provided webhook URLs at your application boundary before passing them to the library.
- Parse the URL yourself with net/url and check u.Scheme before constructing the push config request.
Example fix
// before webhook := "file:///tmp/callback" // or "agents.example.com/hook" (no scheme) // after webhook := "https://agents.example.com/hook"
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(callback)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return fmt.Errorf("callback must be http(s): %q", callback)
} Type guard
func isHTTPScheme(u *url.URL) bool {
return u != nil && (u.Scheme == "http" || u.Scheme == "https")
} Prevention
- Always require https:// in production webhook configs
- Sanitize user-supplied URLs at the application boundary
- Reject bare-host strings missing a scheme during config load
When it happens
Trigger: Calling SetPushNotificationConfig / PushNotificationConfig with a callback URL like 'file:///etc/passwd', 'gopher://...', or an empty/garbled scheme string.
Common situations: User-supplied webhook URL passed through unvalidated; a config typo dropping the 'http(s)://' prefix so the URL parser yields an empty or wrong scheme; deliberately crafted input in a multi-tenant deployment.
Related errors
- push callback host %q resolves to a blocked address %s
- push callback url has no host
- push callback: refusing to connect to blocked address %s
- ai model is nil
- ErrMissingTopic
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/0a0fb3663f333dc4.
Report an issue: GitHub.