{"record":{"id":"d56bbf604775b3ed","repo":"Billionmail/BillionMail","slug":"failed-to-convert-overview-data-v-d56bbf","errorCode":null,"errorMessage":"failed to convert overview data: %v","messagePattern":"failed to convert overview data: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/overview/overview_v1_overview.go","lineNumber":33,"sourceCode":"func (c *ControllerV1) Overview(ctx context.Context, req *v1.OverviewReq) (res *v1.OverviewRes, err error) {\n\tres = &v1.OverviewRes{}\n\n\tif req.EndTime == 0 {\n\t\treq.EndTime = time.Now().Unix()\n\t}\n\n\tif req.EndTime < req.StartTime {\n\t\terr = fmt.Errorf(\"start time must be greater or equal to end time\")\n\t\treturn\n\t}\n\n\toverview := maillog_stat.NewOverview()\n\toverviewMap := overview.Overview(req.CampaignId, req.Domain, req.StartTime, req.EndTime)\n\n\terr = gconv.Struct(overviewMap, &res.Data)\n\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed to convert overview data: %v\", err)\n\t\treturn\n\t}\n\n\tres.SetSuccess(public.LangCtx(ctx, \"Success\"))\n\n\treturn\n}\n","sourceCodeStart":15,"sourceCodeEnd":41,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/overview/overview_v1_overview.go#L15-L41","documentation":"Overview calls maillog_stat's Overview to get a statistics map, then converts it into res.Data with gconv.Struct. Any conversion failure — incompatible field types, unexpected map shape, nil input — is wrapped as 'failed to convert overview data'.","triggerScenarios":"The overview service returning a map whose keys/value types do not match res.Data's expected struct (e.g. string vs int for counts), or a nil/empty map where a populated one is required.","commonSituations":"Refactor changed the service's returned map keys; DB aggregates returning NULL or decimal types that don't fit int fields; API contract drift between deployed service and controller versions.","solutions":["Read the wrapped conversion error to identify the offending field","Update res.Data struct tags/types to match the service's output map keys","Handle nullable/NULL DB values with pointer or sql nullable types","Add a regression test that runs gconv.Struct against real service output"],"exampleFix":"// before\nerr = gconv.Struct(overviewMap, &res.Data)\n// after\nif overviewMap == nil { overviewMap = map[string]interface{}{} }\nif err := gconv.Struct(overviewMap, &res.Data); err != nil {\n    err = fmt.Errorf(\"failed to convert overview data: %v\", err)\n}","handlingStrategy":"try-catch","validationCode":"if (overviewMap == null) throw new Error('overview map is empty');","typeGuard":"function isOverviewMap(x: unknown): x is Record<string, unknown> {\n  return typeof x === 'object' && x !== null;\n}","tryCatchPattern":"try {\n  const data = await api.overview(params);\n} catch (err) {\n  if (String(err.message).startsWith('failed to convert overview data')) {\n    // log wrapped cause and report schema mismatch\n    console.error(err);\n  }\n}","preventionTips":["Version the service->controller data contract","Test gconv.Struct conversion against realistic service output","Map DB NULLs to pointers/zero values before conversion"],"tags":["goframe","type-conversion","serialization"],"backgroundTag":"struct-conversion-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"}