{"record":{"id":"b3d7fd0d90219b93","repo":"vxcontrol/pentagi","slug":"knowledge-list-by-flow-user-w","errorCode":null,"errorMessage":"knowledge: list by flow (user): %w","messagePattern":"knowledge: list by flow \\(user\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/database/knowledge/knowledge.go","lineNumber":287,"sourceCode":"\t\tfor _, r := range rows {\n\t\t\tdocs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))\n\t\t}\n\t}\n\n\treturn applyGoFilters(docs, filter), nil\n}\n\n// ---- ListUserDocuments (user-scoped) ----------------------------------------\n\nfunc (ks *knowledgeStore) ListUserDocuments(ctx context.Context, userID int64, filter *model.KnowledgeFilter, withContent bool) ([]*model.KnowledgeDocument, error) {\n\tuserIDStr := strconv.FormatInt(userID, 10)\n\tvar docs []*model.KnowledgeDocument\n\n\tif filter != nil && filter.FlowID != nil {\n\t\t// Flow-scoped listing; user_id check applied in Go for safety.\n\t\trows, err := ks.db.ListFlowKnowledgeDocuments(ctx, nsOf(strconv.FormatInt(*filter.FlowID, 10)))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"knowledge: list by flow (user): %w\", err)\n\t\t}\n\t\tfor _, r := range rows {\n\t\t\tmeta := parseMeta(nullStr(r.Cmetadata))\n\t\t\tif strconv.FormatInt(meta.UserID, 10) != userIDStr {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdocs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))\n\t\t}\n\t} else {\n\t\trows, err := ks.db.ListUserKnowledgeDocuments(ctx, nsOf(userIDStr))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"knowledge: list user docs: %w\", err)\n\t\t}\n\t\tfor _, r := range rows {\n\t\t\tdocs = append(docs, rowToModel(r.ID, r.Document, nullStr(r.Cmetadata), withContent))\n\t\t}\n\t}\n","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/database/knowledge/knowledge.go#L269-L305","documentation":"ListUserDocuments mirrors ListDocuments but additionally filters rows in Go by user_id parsed from document metadata. When the flow-scoped query (ListFlowKnowledgeDocuments) fails, the error is wrapped as \"knowledge: list by flow (user): %w\". The cause is the underlying DB query, not the user filtering.","triggerScenarios":"Calling ListUserDocuments(ctx, userID, filter with FlowID, withContent) when the flow-scoped pgvector query fails: DB unreachable, timeout, extension error, or malformed metadata that breaks downstream parsing (error surfaces here first as a query failure).","commonSituations":"User-facing knowledge listing for a flow whose DB connection dropped; metadata written by older versions lacking user_id (causes empty results or downstream parse issues); pool exhaustion; pgvector upgrade mismatches.","solutions":["Unwrap and inspect the wrapped DB error; check PostgreSQL logs.","Verify database connectivity and pgvector extension health.","Ensure knowledge documents carry user_id in metadata (re-index legacy documents) so per-user filtering works.","Scope or paginate the query if the flow has many documents.","Retry transient connection failures with backoff."],"exampleFix":"// before\nrows, err := ks.db.ListFlowKnowledgeDocuments(ctx, ns)\nif err != nil {\n    return nil, fmt.Errorf(\"knowledge: list by flow (user): %w\", err)\n}\n// after\nrows, err := ks.db.ListFlowKnowledgeDocuments(ctx, ns)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return nil, ErrKnowledgeListTimeout\n    }\n    return nil, fmt.Errorf(\"knowledge: list by flow (user): %w\", err)\n}","handlingStrategy":"retry","validationCode":"if userID == \"\" || filter == nil || filter.FlowID == nil || *filter.FlowID <= 0 {\n    return fmt.Errorf(\"user listing requires userID and valid FlowID\")\n}\nif err := ctx.Err(); err != nil {\n    return nil, err\n}","typeGuard":"func isDBConnError(err error) bool {\n    var pgErr *pgconn.PgError\n    return errors.As(err, &pgErr) && (pgErr.Code == \"08006\" || pgErr.Code == \"08003\") ||\n        errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"docs, err := kStore.ListUserDocuments(ctx, userID, filter, withContent)\nif err != nil {\n    if isDBConnError(err) {\n        docs, err = retryWithBackoff(3, func() ([]*model.KnowledgeDocument, error) {\n            return kStore.ListUserDocuments(ctx, userID, filter, withContent)\n        })\n    }\n    if err != nil { return nil, fmt.Errorf(\"user knowledge list: %w\", err) }\n}","preventionTips":["Ensure knowledge documents are indexed with user_id metadata at creation time.","Re-index legacy documents missing user_id so per-user filtering behaves.","Retry transient connection failures instead of failing user requests immediately.","Monitor DB health; pool exhaustion is the most common root cause."],"tags":["go","database","postgres","pgvector","query-failed"],"backgroundTag":"database-query-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}