vxcontrol/pentagi · error
knowledge: get user document %s: %w
Error message
knowledge: get user document %s: %w
What it means
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>'.
Source
Thrown at backend/pkg/database/knowledge/knowledge.go:327
// ---- GetDocument (admin) ----------------------------------------------------
func (ks *knowledgeStore) GetDocument(ctx context.Context, id string) (*model.KnowledgeDocument, error) {
row, err := ks.db.GetKnowledgeDocument(ctx, id)
if err != nil {
return nil, fmt.Errorf("knowledge: get document %s: %w", id, err)
}
return rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil
}
// ---- GetUserDocument (user-scoped) ------------------------------------------
func (ks *knowledgeStore) GetUserDocument(ctx context.Context, userID int64, id string) (*model.KnowledgeDocument, error) {
row, err := ks.db.GetUserKnowledgeDocument(ctx, database.GetUserKnowledgeDocumentParams{
Uuid: id,
UserID: nsOf(strconv.FormatInt(userID, 10)),
})
if err != nil {
return nil, fmt.Errorf("knowledge: get user document %s: %w", id, err)
}
return rowToModel(row.ID, row.Document, nullStr(row.Cmetadata), true), nil
}
// ---- SearchDocuments (admin) ------------------------------------------------
func (ks *knowledgeStore) SearchDocuments(ctx context.Context, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {
return ks.doSearch(ctx, 0, query, filter, limit)
}
// ---- SearchUserDocuments (user-scoped) --------------------------------------
func (ks *knowledgeStore) SearchUserDocuments(ctx context.Context, userID int64, query string, filter *model.KnowledgeFilter, limit int) ([]*model.KnowledgeDocumentWithScore, error) {
return ks.doSearch(ctx, userID, query, filter, limit)
}
// doSearch performs a parameterised vector similarity search and returns
// matched documents with their cosine-similarity scores and correct UUIDs.View on GitHub (pinned to ea665308ba)
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.
Example fix
// before
if err != nil {
return nil, fmt.Errorf("knowledge: get user document %s: %w", id, err)
}
// after
if errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("knowledge: document %s not found for user", id) // 404 upstream
}
if err != nil {
return nil, fmt.Errorf("knowledge: get user document %s: %w", id, err)
} Defensive patterns
Strategy: type-guard
Validate before calling
if _, err := uuid.Parse(id); err != nil || userID <= 0 {
return nil, fmt.Errorf("invalid id or user")
} Type guard
func isNotFoundOrForbidden(err error) bool {
return errors.Is(err, sql.ErrNoRows) // ownership miss and absence both surface as no rows
} Try / catch
doc, err := store.GetUserDocument(ctx, userID, id)
if err != nil {
if isNotFoundOrForbidden(err) {
return ErrNotFound // never reveal existence of other users' docs
}
return err
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- failed to get screenshot: %w
- failed to get search log: %w
- failed to get tool call log: %w
- failed to get termlog: %w
- failed to get vector store log: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/4bcb15a8c0482272.
Report an issue: GitHub.