{"record":{"id":"0b8e09338acdbd74","repo":"siyuan-note/siyuan","slug":"image-generation-was-cancelled","errorCode":null,"errorMessage":"image generation was cancelled","messagePattern":"image generation was cancelled","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/assets.go","lineNumber":548,"sourceCode":"\tif prompt == \"\" {\n\t\treturn GenerateImageResult{}, errors.New(\"prompt is required for image generation\")\n\t}\n\tsize := multimodalValueOrDefault(request.Size, Conf.AI.ImageGeneration.Size)\n\tquality := multimodalValueOrDefault(request.Quality, Conf.AI.ImageGeneration.Quality)\n\toutputFormat := strings.ToLower(multimodalValueOrDefault(request.OutputFormat, Conf.AI.ImageGeneration.OutputFormat))\n\tif outputFormat != \"png\" && outputFormat != \"jpeg\" && outputFormat != \"webp\" {\n\t\treturn GenerateImageResult{}, errors.New(\"unsupported image output format\")\n\t}\n\tgenerated, err := util.NewOpenAIImageAdapter(\n\t\tprovider.APIKey, provider.BaseURL, generationModel.Name, Conf.AI.ImageGeneration.RequestTimeout, ResolveAIProviderHeaders(provider),\n\t).Generate(ctx, util.GenerateImageRequest{\n\t\tPrompt: prompt, Size: size, Quality: quality, OutputFormat: outputFormat,\n\t})\n\tif err != nil {\n\t\treturn GenerateImageResult{}, markImageExecutionUnknown(fmt.Errorf(\"generate image failed: %w\", err))\n\t}\n\tif ctx.Err() != nil {\n\t\treturn GenerateImageResult{}, markImageExecutionUnknown(errors.New(\"image generation was cancelled\"))\n\t}\n\treturn GenerateImageResult{\n\t\tData: generated.Data, MIMEType: generated.MIMEType, Extension: generated.Extension, RevisedPrompt: generated.RevisedPrompt,\n\t}, nil\n}\n\n// GenerateDocumentImage 使用通用图片生成能力创建文档资源。\nfunc GenerateDocumentImage(ctx context.Context, request GenerateDocumentImageRequest) (GenerateDocumentImageResult, error) {\n\tbt, err := resolveMultimodalDocument(request.DocumentID)\n\tif err != nil {\n\t\treturn GenerateDocumentImageResult{}, err\n\t}\n\tgenerated, err := GenerateImage(ctx, GenerateImageRequest{\n\t\tPrompt: request.Prompt, Size: request.Size, Quality: request.Quality, OutputFormat: request.OutputFormat,\n\t})\n\tif err != nil {\n\t\treturn GenerateDocumentImageResult{}, err\n\t}","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/assets.go#L530-L566","documentation":"After the adapter call succeeds, GenerateImage checks ctx.Err(); if the caller's context was cancelled or its deadline expired during generation, the result is discarded and \"image generation was cancelled\" is returned (also marked as execution-unknown). This prevents committing images whose generation the caller no longer wants.","triggerScenarios":"The caller's context.Context is cancelled (user aborted, request shut down) or its deadline passes while the provider request is in flight or just as it completes.","commonSituations":"Closing the AI chat panel mid-generation; an HTTP client disconnecting cancels the gin request context; a short parent deadline (e.g. 30s) expiring before a slow provider finishes.","solutions":["Retry with a fresh, non-cancelled context if the generation is still wanted","Use context.WithTimeout with a generous deadline (at least Conf.AI.ImageGeneration.RequestTimeout plus margin)","If cancellation is intentional (user abort), treat this error as expected and skip reporting it to the user"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(ctx, 10*time.Second)\ndefer cancel()\n// after\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\ndefer cancel()\nresult, err := model.GenerateImage(ctx, req)","handlingStrategy":"try-catch","validationCode":"if ctx.Err() != nil {\n    return errors.New(\"context already cancelled before generation started\")\n}","typeGuard":null,"tryCatchPattern":"res, err := model.GenerateImage(ctx, req)\nif err != nil && err.Error() == \"image generation was cancelled\" {\n    if errors.Is(ctx.Err(), context.DeadlineExceeded) {\n        // retry with a longer deadline\n    }\n    // user-initiated cancellation: log and return quietly\n}","preventionTips":["Use a timeout comfortably larger than Conf.AI.ImageGeneration.RequestTimeout","Avoid tying the generation context to short-lived UI lifecycles","Treat cancellation errors as user intent, not failures, in logs"],"tags":["context","cancellation","ai"],"backgroundTag":"request-timeout","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"}