Billionmail/BillionMail · error

failed to query group: %w

Error message

failed to query group: %w

What it means

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.

Source

Thrown at core/internal/controller/batch_mail/batch_mail_v1_api_mail_send.go:189

	if err != nil || emailTemplate.Id == 0 {
		return nil, gerror.New(public.LangCtx(ctx, "Email template does not exist"))
	}
	return &emailTemplate, nil
}

// ensure contact and group exists
func ensureContactAndGroup(ctx context.Context, email string, apiId int) (entity.Contact, error) {
	var contact entity.Contact
	now := int(time.Now().Unix())

	apiGroupName := fmt.Sprintf("api_group_%d", apiId)
	var group entity.ContactGroup
	err := g.DB().Model("bm_contact_groups").Where("name", apiGroupName).Scan(&group)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			group = entity.ContactGroup{}
		} else {
			return contact, fmt.Errorf("failed to query group: %w", err)
		}
	}
	if group.Id == 0 {
		groupResult, err := g.DB().Model("bm_contact_groups").Insert(g.Map{
			"name":        apiGroupName,
			"description": fmt.Sprintf(public.LangCtx(ctx, "API %d automatically created contact group"), apiId),
			"create_time": now,
			"update_time": now,
		})
		if err != nil {
			return contact, err
		}
		groupId, _ := groupResult.LastInsertId()
		group.Id = int(groupId)
	} else {

		count, err := g.DB().Model("bm_contacts").
			Where("email", email).

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Validate the docker-compose.yml has a top-level 'services:' mapping before calling the rebuild
  2. Fix YAML syntax errors so 'services' parses as a map — inspect the parsed config with a debug dump
  3. Point the ConfigManager at the correct compose file (the main BillionMail one)
  4. Restore the original BillionMail docker-compose.yml

Example fix

# before (empty/broken file)
# (no services key)
# after
services:
  postfix-billionmail:
    image: billionmail/postfix
Defensive patterns

Strategy: validation

Validate before calling

cfg, err := parseYAML(composePath)
if err != nil { return err }
services, ok := cfg["services"].(map[string]interface{})
if !ok || len(services) == 0 {
	return fmt.Errorf("docker-compose.yml has no services mapping")
}

Type guard

func hasServicesMap(cfg map[string]interface{}) bool {
	m, ok := cfg["services"].(map[string]interface{})
	return ok && m != nil
}

Try / catch

if err := m.rebuildPostfixServiceNetworks(cfg, configs); err != nil {
	if strings.Contains(err.Error(), "missing 'services'") {
		// reload/repair the compose file before retrying
	}
	return err
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/516b23f48301afce. Report an issue: GitHub.