{"record":{"id":"3ebf76cc127877b3","repo":"siyuan-note/siyuan","slug":"image-operation-failed","errorCode":null,"errorMessage":"image operation failed","messagePattern":"image operation failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/image.go","lineNumber":346,"sourceCode":"\tbt := treenode.GetBlockTree(documentID)\n\tif bt == nil {\n\t\treturn false\n\t}\n\t_, err := model.GetAssetAbsPathInBox(assetPath, bt.BoxID)\n\treturn err == nil\n}\n\nfunc imageJSON(value any) CallToolResult {\n\tdata, err := json.Marshal(value)\n\tif err != nil {\n\t\treturn imageError(err.Error())\n\t}\n\treturn CallToolResult{Content: []ContentItem{{Type: \"text\", Text: string(data)}}}\n}\n\nfunc imageError(message string) CallToolResult {\n\tif message == \"\" {\n\t\tmessage = errors.New(\"image operation failed\").Error()\n\t}\n\treturn CallToolResult{Content: []ContentItem{{Type: \"text\", Text: message}}, IsError: true}\n}\n\nfunc imageResultForError(err error) CallToolResult {\n\tif model.IsImageExecutionUnknown(err) {\n\t\treturn imageUnknown(err.Error())\n\t}\n\treturn imageError(err.Error())\n}\n\nfunc imageUnknown(message string) CallToolResult {\n\tresult := imageError(message)\n\tresult.ExecutionUnknown = true\n\treturn result\n}\n","sourceCodeStart":328,"sourceCodeEnd":363,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/tools/image.go#L328-L363","documentation":"imageError builds the error CallToolResult for MCP image tools and substitutes this default message when the caller passes an empty message. It guarantees the tool result is always marked IsError with non-empty text, since an error result with blank content is useless to the MCP client.","triggerScenarios":"Any image tool failure path (imageHandler, imageList, runImageOperation, imageJSON, imageResultForError, imageUnknown) that reaches imageError with an empty message — typically an error value whose Error() is \"\" or a branch that forgets to set a message.","commonSituations":"Wrapping errors that stringify to empty; swallowing the underlying error into an empty variable; callers constructing errors from nil/empty fields; missing i18n or formatting that leaves the message blank.","solutions":["Always pass a descriptive message (or the underlying err.Error()) into imageError instead of \"\"","Use imageResultForError(err) for real error values so classification (e.g. IsImageExecutionUnknown) and messaging are handled","Add a guard/log at call sites where the message is built dynamically to catch empty strings early"],"exampleFix":"// before\nreturn imageError(\"\")\n// after\nreturn imageResultForError(fmt.Errorf(\"render image failed: %w\", err))","handlingStrategy":"try-catch","validationCode":"if (!message || message.trim() === '') {\n  message = 'image operation failed'; // or derive from err\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await imageToolCall(args);\n} catch (err) {\n  return imageResultForError(err); // classifies unknown-execution errors and keeps a non-empty message\n}","preventionTips":["Use imageResultForError for real error values instead of hand-built imageError calls","Include the underlying err.Error() text in the message","Assert in tests that error results always carry non-empty text"],"tags":["image","error-handling","mcp","default-message"],"backgroundTag":"api-error-response","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}