{"record":{"id":"516b23f48301afce","repo":"Billionmail/BillionMail","slug":"failed-to-query-group-w","errorCode":null,"errorMessage":"failed to query group: %w","messagePattern":"failed to query group: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/controller/batch_mail/batch_mail_v1_api_mail_send.go","lineNumber":189,"sourceCode":"\tif err != nil || emailTemplate.Id == 0 {\n\t\treturn nil, gerror.New(public.LangCtx(ctx, \"Email template does not exist\"))\n\t}\n\treturn &emailTemplate, nil\n}\n\n// ensure contact and group exists\nfunc ensureContactAndGroup(ctx context.Context, email string, apiId int) (entity.Contact, error) {\n\tvar contact entity.Contact\n\tnow := int(time.Now().Unix())\n\n\tapiGroupName := fmt.Sprintf(\"api_group_%d\", apiId)\n\tvar group entity.ContactGroup\n\terr := g.DB().Model(\"bm_contact_groups\").Where(\"name\", apiGroupName).Scan(&group)\n\tif err != nil {\n\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\tgroup = entity.ContactGroup{}\n\t\t} else {\n\t\t\treturn contact, fmt.Errorf(\"failed to query group: %w\", err)\n\t\t}\n\t}\n\tif group.Id == 0 {\n\t\tgroupResult, err := g.DB().Model(\"bm_contact_groups\").Insert(g.Map{\n\t\t\t\"name\":        apiGroupName,\n\t\t\t\"description\": fmt.Sprintf(public.LangCtx(ctx, \"API %d automatically created contact group\"), apiId),\n\t\t\t\"create_time\": now,\n\t\t\t\"update_time\": now,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn contact, err\n\t\t}\n\t\tgroupId, _ := groupResult.LastInsertId()\n\t\tgroup.Id = int(groupId)\n\t} else {\n\n\t\tcount, err := g.DB().Model(\"bm_contacts\").\n\t\t\tWhere(\"email\", email).","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/batch_mail/batch_mail_v1_api_mail_send.go#L171-L207","documentation":"rebuildPostfixServiceNetworks operates on the docker-compose config parsed into a map and requires a top-level 'services' key of type map[string]interface{}. It throws this error when the key is absent or has a different type (e.g. null, a list), meaning the YAML is not a valid compose file structure.","triggerScenarios":"Calling rebuildPostfixServiceNetworks with a config map parsed from a YAML file that lacks 'services' or where 'services' is not a mapping (empty file, malformed YAML that decodes to nil, wrong file passed).","commonSituations":"Empty or corrupt docker-compose.yml, a YAML file that parsed 'services' as something other than a map, or passing a partial config fragment instead of a full compose document.","solutions":["Validate the docker-compose.yml has a top-level 'services:' mapping before calling the rebuild","Fix YAML syntax errors so 'services' parses as a map — inspect the parsed config with a debug dump","Point the ConfigManager at the correct compose file (the main BillionMail one)","Restore the original BillionMail docker-compose.yml"],"exampleFix":"# before (empty/broken file)\n# (no services key)\n# after\nservices:\n  postfix-billionmail:\n    image: billionmail/postfix","handlingStrategy":"validation","validationCode":"cfg, err := parseYAML(composePath)\nif err != nil { return err }\nservices, ok := cfg[\"services\"].(map[string]interface{})\nif !ok || len(services) == 0 {\n\treturn fmt.Errorf(\"docker-compose.yml has no services mapping\")\n}","typeGuard":"func hasServicesMap(cfg map[string]interface{}) bool {\n\tm, ok := cfg[\"services\"].(map[string]interface{})\n\treturn ok && m != nil\n}","tryCatchPattern":"if err := m.rebuildPostfixServiceNetworks(cfg, configs); err != nil {\n\tif strings.Contains(err.Error(), \"missing 'services'\") {\n\t\t// reload/repair the compose file before retrying\n\t}\n\treturn err\n}","preventionTips":["Run 'docker compose config -q' after any manual YAML edit","Keep atomic writes (write temp file + rename) so compose files are never truncated","Snapshot the compose file before programmatic modification","Verify the parsed map is non-empty before rebuilding"],"tags":["docker-compose","multi-ip","yaml","type-assertion"],"backgroundTag":"missing-compose-services-key","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"}