{"record":{"id":"ea57273b6ac21bcc","repo":"Tencent/WeKnora","slug":"a-message-can-use-at-most-d-attachments","errorCode":null,"errorMessage":"a message can use at most %d attachments","messagePattern":"a message can use at most (.+?) attachments","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/temporary_document.go","lineNumber":600,"sourceCode":"\t\tout = append(out, ref.ImageData)\n\t\tif len(out) >= limit {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn out\n}\n\n// approxTextContentRunes counts the runes of real text in markdown, ignoring\n// image references, so scanned/image-only documents register as low-text.\nfunc approxTextContentRunes(md string) int {\n\tstripped := markdownImagePattern.ReplaceAllString(md, \"\")\n\treturn len([]rune(strings.TrimSpace(stripped)))\n}\n\nfunc (s *temporaryDocumentService) ResolveForPrompt(ctx context.Context, tenantID uint64, sessionID string, documentIDs []string, query string) (*types.TemporaryDocumentPromptResult, error) {\n\tresult := &types.TemporaryDocumentPromptResult{}\n\tif len(documentIDs) > types.MaxTemporaryAttachmentsPerMessage {\n\t\treturn nil, fmt.Errorf(\"a message can use at most %d attachments\", types.MaxTemporaryAttachmentsPerMessage)\n\t}\n\tperDocumentBudget := temporaryDocumentPromptBudget\n\tif len(documentIDs) > 0 {\n\t\tperDocumentBudget = temporaryDocumentPromptBudget / len(documentIDs)\n\t}\n\tseen := make(map[string]struct{}, len(documentIDs))\n\tfor _, documentID := range documentIDs {\n\t\tif _, duplicate := seen[documentID]; duplicate {\n\t\t\tcontinue\n\t\t}\n\t\tseen[documentID] = struct{}{}\n\t\tdocument, err := s.repo.GetScoped(ctx, tenantID, sessionID, documentID)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif document == nil {\n\t\t\treturn nil, fmt.Errorf(\"attachment %s was not found in this session\", documentID)\n\t\t}","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/temporary_document.go#L582-L618","documentation":"ResolveForPrompt enforces types.MaxTemporaryAttachmentsPerMessage as a hard cap on how many temporary documents may be attached to a single chat message. Exceeding the cap aborts before any document lookup.","triggerScenarios":"Calling ResolveForPrompt (via the chat/message send path) with a documentIDs slice longer than MaxTemporaryAttachmentsPerMessage.","commonSituations":"Client allows unlimited attachment selection in the UI; API consumer sends a large documentIDs array directly; batch message built from prior session references.","solutions":["Limit the attachments selected to MaxTemporaryAttachmentsPerMessage before sending","Update the client UI to enforce the same cap at selection time","Split the content across multiple messages if more attachments are needed","Raise MaxTemporaryAttachmentsPerMessage consciously if the cap is genuinely too low"],"exampleFix":"// before\nif len(documentIDs) > MaxTemporaryAttachmentsPerMessage { ... }\n// after\nif len(documentIDs) > MaxTemporaryAttachmentsPerMessage {\n    documentIDs = documentIDs[:MaxTemporaryAttachmentsPerMessage]\n}","handlingStrategy":"validation","validationCode":"if len(documentIDs) > types.MaxTemporaryAttachmentsPerMessage {\n    return errors.New(\"too many attachments\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enforce the attachment cap in the UI at selection time","Never send unchecked documentIDs arrays from API clients"],"tags":["validation","limit","attachments"],"backgroundTag":"request-limit-exceeded","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}