{"record":{"id":"4bcb15a8c0482272","repo":"vxcontrol/pentagi","slug":"knowledge-get-user-document-s-w","errorCode":null,"errorMessage":"knowledge: get user document %s: %w","messagePattern":"knowledge: get user document (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/database/knowledge/knowledge.go","lineNumber":327,"sourceCode":"// ---- GetDocument (admin) ----------------------------------------------------\n\nfunc (ks *knowledgeStore) GetDocument(ctx context.Context, id string) (*model.KnowledgeDocument, error) {\n\trow, err := ks.db.GetKnowledgeDocument(ctx, id)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"knowledge: get document %s: %w\", id, err)\n\t}\n\treturn rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil\n}\n\n// ---- GetUserDocument (user-scoped) ------------------------------------------\n\nfunc (ks *knowledgeStore) GetUserDocument(ctx context.Context, userID int64, id string) (*model.KnowledgeDocument, error) {\n\trow, err := ks.db.GetUserKnowledgeDocument(ctx, database.GetUserKnowledgeDocumentParams{\n\t\tUuid:   id,\n\t\tUserID: nsOf(strconv.FormatInt(userID, 10)),\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"knowledge: get user document %s: %w\", id, err)\n\t}\n\treturn rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil\n}\n\n// ---- SearchDocuments (admin) ------------------------------------------------\n\nfunc (ks *knowledgeStore) SearchDocuments(ctx context.Context, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {\n\treturn ks.doSearch(ctx, 0, query, filter, limit)\n}\n\n// ---- SearchUserDocuments (user-scoped) --------------------------------------\n\nfunc (ks *knowledgeStore) SearchUserDocuments(ctx context.Context, userID int64, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {\n\treturn ks.doSearch(ctx, userID, query, filter, limit)\n}\n\n// doSearch performs a parameterised vector similarity search and returns\n// matched documents with their cosine-similarity scores and correct UUIDs.","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/database/knowledge/knowledge.go#L309-L345","documentation":"GetUserDocument fetches a knowledge document by UUID enforcing ownership via user_id in cmetadata. Failure of the SQLC query GetUserKnowledgeDocument (not found, not owned, DB down) is wrapped as 'knowledge: get user document <id>'.","triggerScenarios":"Calling GetUserDocument or the user-scoped Update/Rename/Delete wrappers with a document id that either does not exist or belongs to a different user (UUID + UserID pair has no row).","commonSituations":"A user tries to access another user's document id (authorization failure); user_id stored under a different namespace format than nsOf produces; stale id from a deleted document.","solutions":["Verify the document exists and is owned by the given userID (check cmetadata user_id in the database).","Map sql.ErrNoRows to a 404-style not-found response for the UI instead of leaking a DB error.","Ensure the userID namespace string (nsOf) format matches what was written at CreateDocument time.","Check DB connectivity if the wrapped error indicates connection failure."],"exampleFix":"// before\nif err != nil {\n    return nil, fmt.Errorf(\"knowledge: get user document %s: %w\", id, err)\n}\n// after\nif errors.Is(err, sql.ErrNoRows) {\n    return nil, fmt.Errorf(\"knowledge: document %s not found for user\", id) // 404 upstream\n}\nif err != nil {\n    return nil, fmt.Errorf(\"knowledge: get user document %s: %w\", id, err)\n}","handlingStrategy":"type-guard","validationCode":"if _, err := uuid.Parse(id); err != nil || userID <= 0 {\n    return nil, fmt.Errorf(\"invalid id or user\")\n}","typeGuard":"func isNotFoundOrForbidden(err error) bool {\n    return errors.Is(err, sql.ErrNoRows) // ownership miss and absence both surface as no rows\n}","tryCatchPattern":"doc, err := store.GetUserDocument(ctx, userID, id)\nif err != nil {\n    if isNotFoundOrForbidden(err) {\n        return ErrNotFound // never reveal existence of other users' docs\n    }\n    return err\n}","preventionTips":["Always return not-found (not forbidden) on ownership misses to avoid id enumeration.","Keep the nsOf namespace format consistent between write and read paths.","Test the ownership filter with cross-user access attempts.","Check cmetadata user_id values after schema changes."],"tags":["database","not-found","authorization"],"backgroundTag":"record-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}