mastra-ai/mastra · error
Push notification URL must not target local or private IPs:
Error message
Push notification URL must not target local or private IPs: ${hostname} What it means
The sender rejects push notification URLs whose hostname is itself a local or private IP address (127.0.0.0/8, 10/8, 172.16/12, 192.168/16, link-local, etc.) via isDisallowedIpAddress, again to prevent server-side request forgery into internal networks.
Source
Thrown at packages/server/src/server/a2a/push-notification-sender.ts:95
private async resolveValidatedDestination(rawUrl: string) {
const url = new URL(rawUrl);
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
throw new Error(`Push notification URL must use http or https: ${url.protocol}`);
}
const hostname = url.hostname.toLowerCase();
if (this.options.allowedHosts && !this.options.allowedHosts.includes(hostname)) {
throw new Error(`Push notification host is not allowed: ${hostname}`);
}
if (isDisallowedHostname(hostname)) {
throw new Error(`Push notification URL must not target local or internal hosts: ${hostname}`);
}
if (isDisallowedIpAddress(hostname)) {
throw new Error(`Push notification URL must not target local or private IPs: ${hostname}`);
}
const resolvedAddresses =
isIP(hostname) === 0
? await (this.options.lookup ?? defaultLookup)(hostname, { all: true, verbatim: true })
: [{ address: hostname, family: isIP(hostname) }];
if (resolvedAddresses.some(result => isDisallowedIpAddress(result.address))) {
throw new Error(`Push notification URL resolved to a local or private IP: ${hostname}`);
}
const requestUrl = new URL(url.toString());
requestUrl.hostname = resolvedAddresses[0]!.address;
return {
originalUrl: url,
requestUrl,
hostHeader: url.host,View on GitHub (pinned to 75dd419e61)
Solutions
- Use a DNS hostname backed by a public IP for the push endpoint
- For local dev, tunnel the receiver publicly or use an address that passes the private-IP check
- If internal delivery is truly required, deploy a reverse proxy with a public hostname that forwards to the internal service
Example fix
// before url: 'http://192.168.1.10:4111/a2a/push' // after url: 'https://a2a-push.example.com/a2a/push'
Defensive patterns
Strategy: validation
Validate before calling
import { isIP } from 'node:net';
function assertNonPrivateIpHost(raw: string) {
const host = new URL(raw).hostname;
if (isIP(host) !== 0 && /^(127\.|10\.|192\.168\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.)/.test(host)) {
throw new Error(`Refusing private IP host: ${host}`);
}
} Try / catch
try {
await sender.sendNotifications(task, configs);
} catch (err) {
if (err instanceof Error && err.message.includes('must not target local or private IPs')) {
logger.warn('Private-IP push target rejected', { err: err.message });
} else throw err;
} Prevention
- Use DNS names, not literal IPs, for push endpoints
- Exclude loopback/link-local/RFC1918 literals in webhook input validation
- Put internal receivers behind a publicly addressed reverse proxy
When it happens
Trigger: A push notification URL uses a literal private/loopback IP as the host, e.g. 'http://127.0.0.1:4111/callback', 'http://10.0.0.5/hook', 'http://169.254.169.254/...'.
Common situations: Local testing against a dev server bound to loopback, container-to-container calls using bridge-network IPs, misconfigured Kubernetes in-cluster callback addresses, or copying an internal service address into the push config.
Related errors
- Push notification URL must not target local or internal host
- URL resolves to a private or reserved address.
- Push notification URL must use http or https: ${url.protocol
- Push notification host is not allowed: ${hostname}
- Push notification URL resolved to a local or private IP: ${h
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/8ce92a8fd1c117b4.
Report an issue: GitHub.