{"record":{"id":"dc6352b5aa5d6e93","repo":"vxcontrol/pentagi","slug":"resource-d-not-found","errorCode":null,"errorMessage":"resource %d not found","messagePattern":"resource (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/server/services/assistants.go","lineNumber":674,"sourceCode":"\tif !isAdmin && !slices.Contains(privs, \"resources.view\") && len(ids) > 0 {\n\t\treturn nil, fmt.Errorf(\"permission 'resources.view' required to use resource IDs\")\n\t}\n\n\tvar recs []models.UserResource\n\tif err := db.Model(&models.UserResource{}).Where(\"id IN (?)\", ids).Find(&recs).Error; err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch resources: %w\", err)\n\t}\n\n\tfound := make(map[uint64]models.UserResource, len(recs))\n\tfor _, r := range recs {\n\t\tfound[r.ID] = r\n\t}\n\n\tresult := make([]database.UserResource, 0, len(ids))\n\tfor _, id := range ids {\n\t\tr, ok := found[id]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"resource %d not found\", id)\n\t\t}\n\t\tif !isAdmin && r.UserID != uid {\n\t\t\treturn nil, fmt.Errorf(\"resource %d not accessible\", id)\n\t\t}\n\t\tresult = append(result, database.UserResource{\n\t\t\tID:        int64(r.ID),\n\t\t\tUserID:    int64(r.UserID),\n\t\t\tHash:      r.Hash,\n\t\t\tName:      r.Name,\n\t\t\tPath:      r.Path,\n\t\t\tSize:      r.Size,\n\t\t\tIsDir:     r.IsDir,\n\t\t\tCreatedAt: database.TimeToNullTime(r.CreatedAt),\n\t\t\tUpdatedAt: database.TimeToNullTime(r.UpdatedAt),\n\t\t})\n\t}\n\n\treturn result, nil","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/assistants.go#L656-L692","documentation":"After fetching the referenced rows, validateServiceResources builds a map and verifies every requested ID actually resolved to a UserResource row. If any requested ID is missing from the database it fails with 'resource %d not found'. Note the query does not pre-filter by user, so existence and ownership are separate checks — this one is pure existence.","triggerScenarios":"CreateFlowAssistant, PatchAssistant, CreateFlow, or PatchFlow called with a resource ID that does not exist in the user_resources table (already deleted, wrong ID from another environment, or typographical error).","commonSituations":"Resource deleted by another user/session while the client kept a stale ID; copying IDs between dev/staging/prod databases; frontend caching an old resource list; hard-coded IDs in automation scripts after a DB reset.","solutions":["Refresh the resource list (GET resources) and resend valid IDs.","Remove the stale ID from the request payload.","If the resource was deleted intentionally, update dependent flows/assistants to drop the reference.","Check for environment mismatch if the ID exists in another database.","Verify no recent migration or cleanup job purged user_resources rows."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// fetch current valid resource IDs for the caller before referencing them\nvar valid []int64\ndb.Model(&models.UserResource{}).Where(\"id IN ?\", ids).Pluck(\"id\", &valid)\nmissing := setDifference(ids, valid)\nif len(missing) > 0 {\n    return fmt.Errorf(\"unknown resource IDs: %v — refresh the resource list\", missing)\n}","typeGuard":"func allResourcesExist(ids []uint64, found map[uint64]models.UserResource) bool {\n    for _, id := range ids {\n        if _, ok := found[id]; !ok {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"_, err := validateServiceResources(ctx, uid, privs, ids)\nif err != nil {\n    var nf resourceNotFoundError\n    if strings.Contains(err.Error(), \"not found\") && errors.As(err, &nf) {\n        return nil, fmt.Errorf(\"resource %d no longer exists; refresh your resource list\", nf.ID)\n    }\n    return nil, err\n}","preventionTips":["Refresh cached resource lists before creating flows/assistants","Don't hard-code resource IDs in scripts or cross-environment configs","Handle deletion cascades: remove references when a resource is deleted","Validate IDs client-side against a recent listing"],"tags":["resources","not-found","validation","api"],"backgroundTag":"resource-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}