{"record":{"id":"64279e1abc00844d","repo":"Billionmail/BillionMail","slug":"failed-to-get-contacts-trend-w","errorCode":null,"errorMessage":"failed to get contacts trend: %w","messagePattern":"failed to get contacts trend: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/contact/contact.go","lineNumber":307,"sourceCode":"\n\tvar trends []*ContactTrend\n\n\tdb := g.DB().Model(\"bm_contacts\").\n\t\tFields(\n\t\t\t\"to_char(to_timestamp(create_time), 'YYYY-MM') as month\",\n\t\t\t\"SUM(CASE WHEN active = 1 THEN 1 ELSE 0 END) as subscribe_count\",\n\t\t\t\"SUM(CASE WHEN active = 0 THEN 1 ELSE 0 END) as unsubscribe_count\",\n\t\t).\n\t\tWhere(\"create_time BETWEEN ? AND ?\", startTime.Unix(), endTime.Unix()).\n\t\tGroup(\"month\").\n\t\tOrder(\"month ASC\")\n\n\tif groupId != 0 {\n\t\tdb = db.Where(\"group_id = ?\", groupId)\n\t}\n\n\tif err := db.Scan(&trends); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get contacts trend: %w\", err)\n\t}\n\n\tif trends == nil {\n\t\treturn make([]*ContactTrend, 0), nil\n\t}\n\n\treturn trends, nil\n}\n\nfunc UpdateContactsGroups(ctx context.Context, emails []string, status int, newGroupIds []int) (int, error) {\n\n\tvar existingContacts []struct {\n\t\tEmail   string            `json:\"email\"`\n\t\tAttribs map[string]string `json:\"attribs\"`\n\t\tStatus  int               `json:\"status\"`\n\t}\n\n\terr := g.DB().Model(\"bm_contacts\").","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/contact/contact.go#L289-L325","documentation":"GetContactsTrend queries aggregate contact trend statistics grouped by date. When the underlying PostgreSQL query fails (syntax, connection, bad column, driver error), the db.Scan error is wrapped with this message so the caller knows the trend report could not be produced.","triggerScenarios":"Calling GetContactsTrend with a time range / group filter when the DB is unreachable, the contacts table or required columns (created_at, group_id) are missing or renamed, or the query times out on very large datasets.","commonSituations":"Fresh install where migrations haven't created the tables; schema drift after an upgrade; DB credentials/network changed; filtering on a huge table without an index causing statement timeout.","solutions":["Inspect the wrapped cause (%w) in logs to see the actual SQL error","Run database migrations to ensure the contacts/trend tables and columns exist","Verify DB connectivity and credentials (see InitDatabase errors)","Add an index on the trend time column / narrow the queried date range to avoid timeouts"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if err := db.Ping(); err != nil { return fmt.Errorf(\"db unreachable before trend query: %w\", err) }","typeGuard":null,"tryCatchPattern":"trends, err := contact.GetContactsTrend(from, to, groupId)\nif err != nil {\n    var cause error\n    if errors.As(err, &cause) || true { log.Errorf(\"trend query: %v\", err) }\n    return emptyTrendFallback()\n}","preventionTips":["Run migrations before serving stats endpoints","Narrow date ranges and index the time column","Log the wrapped root cause for diagnosis","Monitor DB connection health"],"tags":["database","query","sql"],"backgroundTag":"database-query-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}