aaif-goose/goose · error
Resource '${fallbackUri}' returned no contents
Error message
Resource '${fallbackUri}' returned no contents What it means
Thrown by flattenReadResourceResult in mcp-apps.ts when an MCP readResource result has no usable contents: either result.contents is missing/not an array, or no element of it passes isRecord. The function expects the standard MCP ReadResourceResult shape ({contents: [{uri, mimeType?, text? | blob?}]}) and takes the first object entry. An empty array means the server acknowledged the read but returned nothing for the requested URI.
Source
Thrown at ui/desktop/src/acp/mcp-apps.ts:51
return isRecord(meta) ? meta : undefined;
}
function decodeBase64Text(blob: string): string {
let bytes: Uint8Array;
if (typeof globalThis.atob === 'function') {
const binary = globalThis.atob(blob);
bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
} else {
bytes = Uint8Array.from(Buffer.from(blob, 'base64'));
}
return new TextDecoder().decode(bytes);
}
function flattenReadResourceResult(result: unknown, fallbackUri: string): McpAppResourceResponse {
const contents = isRecord(result) && Array.isArray(result.contents) ? result.contents : [];
const first = contents.find(isRecord);
if (!first) {
throw new Error(`Resource '${fallbackUri}' returned no contents`);
}
const uri = stringField(first, 'uri') ?? fallbackUri;
const mimeType = stringField(first, 'mimeType') ?? stringField(first, 'mime_type') ?? null;
const text = stringField(first, 'text') ?? decodeBase64Text(stringField(first, 'blob') ?? '');
return {
uri,
mimeType,
text,
_meta: metaField(first),
};
}
function acpApp(value: unknown): GooseApp | null {
if (!isRecord(value)) return null;
return value as GooseApp;
}View on GitHub (pinned to 3810898a74)
Solutions
- Call the server's resources/list and confirm the requested URI exists before reading it.
- Inspect the raw readResource response in devtools/network to see the actual shape — if it is nested, adjust the flattening.
- Fix the MCP server to return an explicit error (or valid contents) instead of an empty contents array.
- If the resource is legitimately empty, handle this error in the caller and show 'resource unavailable' rather than crashing the app flow.
Example fix
// before
const contents = isRecord(result) && Array.isArray(result.contents) ? result.contents : [];
const first = contents.find(isRecord);
if (!first) {
throw new Error(`Resource '${fallbackUri}' returned no contents`);
}
// after (clearer error including what came back)
const contents = isRecord(result) && Array.isArray(result.contents) ? result.contents : [];
const first = contents.find(isRecord);
if (!first) {
throw new Error(`Resource '${fallbackUri}' returned no contents (got ${JSON.stringify(result)?.slice(0, 200)})`);
} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the resource exists before reading it
const listed = await client.readResource ?? null; // placeholder guard for typed clients
async function resourceExists(client: McpClient, uri: string): Promise<boolean> {
const resources = await client.listResources();
return resources.some((r) => r.uri === uri);
} Type guard
function hasResourceContents(
result: unknown
): result is { contents: Record<string, unknown>[] } {
return (
typeof result === 'object' && result !== null &&
Array.isArray((result as { contents?: unknown }).contents) &&
((result as { contents: unknown[] }).contents.length > 0)
);
} Try / catch
try {
const response = await readMcpAppResource(uri);
} catch (error) {
if (/returned no contents/.test(String(error))) {
return { uri, mimeType: null, text: '', _meta: {} }; // or show 'resource unavailable'
}
throw error;
} Prevention
- Check resources/list before deep-linking straight to a read.
- Fix MCP servers to error explicitly on unknown URIs instead of returning empty contents.
- Log the raw result shape when flattening fails to catch schema drift early.
When it happens
Trigger: Calling the MCP app resource fetch (readResource with a fallbackUri) where the app/server does not expose that resource; server bug returning {contents: []}; a response shaped differently (e.g. {result: {contents: [...]}}) so the outer contents check fails; empty resource file behind the server.
Common situations: Deep links or app-install flows requesting a manifest/resource URI the server version no longer serves; MCP server returning 200 with empty contents for unknown URIs instead of an error; schema drift between the server and this client's expectations.
Related errors
- Unsupported extension type for ACP: ${config.type}
- Unknown provider: ${providerId}
- External ACP backend URL is required
- External ACP backend URL must use http: or https:, got ${url
- External ACP backend URL must not include query parameters o
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/8e4e51bce34f4c34.
Report an issue: GitHub.