vercel/ai · warning · Error
Invalid ui/open-link params
Error message
Invalid ui/open-link params
What it means
The bridge validates `ui/open-link` requests and requires a string `url` param. This error is thrown when params are not a JSON object or `params.url` is missing/not a string. It guards the host's openLink callback from malformed iframe input.
Source
Thrown at packages/react/src/mcp-apps/bridge.ts:87
function assertResourceReadParams(params: unknown): { uri: string } {
if (!isJSONObject(params) || typeof params.uri !== 'string') {
throw new Error('Invalid resources/read params');
}
if (!params.uri.startsWith('ui://')) {
throw new Error(
`resources/read is limited to ui:// resources: ${params.uri}`,
);
}
return { uri: params.uri };
}
/**
* Validates `ui/open-link` params and allows only `https:`/`http:`/`mailto:`
* URLs.
*/
function assertOpenLinkParams(params: unknown): { url: string } {
if (!isJSONObject(params) || typeof params.url !== 'string') {
throw new Error('Invalid ui/open-link params');
}
let scheme: string;
try {
scheme = new URL(params.url).protocol;
} catch {
throw new Error(`Invalid ui/open-link url: ${params.url}`);
}
if (scheme !== 'https:' && scheme !== 'http:' && scheme !== 'mailto:') {
throw new Error(`Disallowed ui/open-link scheme: ${scheme}`);
}
return { url: params.url };
}
/**
* Validates params for `ui/request-display-mode`.View on GitHub (pinned to 69428b1f8b)
Solutions
- Ensure the iframe sends `{ method: 'ui/open-link', params: { url: '<string>' } }`.
- Verify the app actually sets the url value before requesting (log it app-side).
- Compare against the MCP Apps `ui/open-link` schema if using a custom iframe client.
- Check the host `onError` callback for the raw request payload.
Example fix
// before
openLink({ href: 'https://example.com' })
// after
openLink({ url: 'https://example.com' }) Defensive patterns
Strategy: validation
Validate before calling
function isValidOpenLinkParams(params: unknown): boolean {
return (
typeof params === 'object' && params !== null && !Array.isArray(params) &&
typeof (params as any).url === 'string'
);
}
// before requesting:
if (!isValidOpenLinkParams({ url })) throw new Error('ui/open-link requires a string url'); Type guard
function isOpenLinkParams(v: unknown): v is { url: string } {
return typeof v === 'object' && v !== null && !Array.isArray(v) &&
typeof (v as any).url === 'string';
} Try / catch
try {
await openLink({ url });
} catch (error) {
if (error instanceof Error && error.message === 'Invalid ui/open-link params') {
console.error('ui/open-link params must be { url: string }');
}
} Prevention
- Use the exact `url` key with a string value.
- Guard against undefined link variables before building the request.
- Validate the params object app-side before posting.
When it happens
Trigger: The iframe posts `ui/open-link` with `params` not an object, no `url` key, or a non-string `url` value (e.g. `{ url: undefined }` or `{ href: 'https://...' }`).
Common situations: App UI builds the link dynamically and the variable is undefined; key typo (`href`/`uri` instead of `url`); a hand-written iframe client deviating from the MCP Apps method schema.
Related errors
- Invalid tools/call params
- Invalid resources/read params
- Invalid ui/open-link url: ${params.url}
- Invalid ui/request-display-mode params
- Invalid MCP App resource URI: ${JSON.stringify(resourceUri)}
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/c6faee42225a891d.
Report an issue: GitHub.