{"record":{"id":"3e51b19946f5da5a","repo":"Foundry376/Mailspring","slug":"attachment-file-displayname-has-not-been-do","errorCode":null,"errorMessage":"Attachment '${file.displayName()}' has not been downloaded — call the get_attachment tool first.","messagePattern":"Attachment '(.+?)' has not been downloaded — call the get_attachment tool first\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/internal_packages/mcp-server/lib/mcp-tools.ts","lineNumber":363,"sourceCode":"        });\n\n      try {\n        // Variables come from the SDK's template match on the raw URI, so\n        // they preserve the ids' case (unlike uri.host, which URL lowercases).\n        const messageId = decodeURIComponent(String(variables.messageId));\n        const fileId = decodeURIComponent(String(variables.fileId));\n\n        const message = await DatabaseStore.find<Message>(Message, messageId);\n        if (!message || !isMessageAllowed(message)) {\n          throw new Error(`Message '${messageId}' not found`);\n        }\n        const file = (message.files || []).find((f) => f.id === fileId);\n        if (!file) {\n          throw new Error(`Message '${messageId}' has no attachment with id '${fileId}'`);\n        }\n        const filePath = await attachmentPathOnDisk(file);\n        if (!filePath) {\n          throw new Error(\n            `Attachment '${file.displayName()}' has not been downloaded — call the get_attachment tool first.`\n          );\n        }\n\n        const buffer = await fs.promises.readFile(filePath);\n        audit('ok');\n        return {\n          contents: [\n            { uri: uri.href, mimeType: mimeTypeForFile(file), blob: buffer.toString('base64') },\n          ],\n        };\n      } catch (err) {\n        audit(`error: ${(err as Error).message}`.slice(0, 100));\n        throw err;\n      }\n    }\n  );\n}","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/Foundry376/Mailspring/blob/648c685d602ece6bb00c22534b8734de6ac644b3/app/internal_packages/mcp-server/lib/mcp-tools.ts#L345-L381","documentation":"Resource handler guard in registerResources: the attachment exists but has no downloaded content in the local files directory. The MCP protocol requires content to be fetched explicitly first, so this directs the client to run the get_attachment tool before reading the resource stream.","triggerScenarios":"Thrown at app/internal_packages/mcp-server/lib/mcp-tools.ts:363 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Call the get_attachment tool for this file, then re-request the resource","Treat the error as an actionable workflow step rather than a failure: expose it in the tool description so clients sequence downloads correctly"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"648c685d602ece6bb00c22534b8734de6ac644b3","analyzedAt":"2026-09-03T02:00:24.311Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}