Billionmail/BillionMail · error

load contact attribs: %w

Error message

load contact attribs: %w

What it means

loadContactAttribs wraps the underlying error from the GoFrame DB query (g.DB().Model("bm_contacts")...Value("attribs")) that fetches the attribs column for a given contact id and group_id. This is a database-layer failure, not a data problem: the wrapped error carries the real cause (connectivity, bad SQL, schema drift). Callers (RunPipeline, updateContactVideoAttribs) surface it and the job is marked failed at the load_contact phase.

Source

Thrown at core/internal/service/video_gen/orchestrator.go:329

	os.RemoveAll(tmpDir)

	return nil
}

// markFailed sets job status to failed with error message and logs it.
func markFailed(ctx context.Context, jobID int, phase string, err error) {
	g.Log().Errorf(ctx, "video job %d failed at %s: %v", jobID, phase, err)
	updateJobStatus(ctx, jobID, JobFailed, phase, err.Error())
}

// loadContactAttribs fetches attribs for a contact from DB.
func loadContactAttribs(ctx context.Context, contactID, groupID int) (map[string]string, error) {
	val, err := g.DB().Model("bm_contacts").Ctx(ctx).
		Where("id", contactID).
		Where("group_id", groupID).
		Value("attribs")
	if err != nil {
		return nil, fmt.Errorf("load contact attribs: %w", err)
	}
	if val.IsNil() || val.IsEmpty() {
		return nil, fmt.Errorf("contact %d has no attribs", contactID)
	}

	result := make(map[string]string)
	if err := val.Scan(&result); err != nil {
		return nil, fmt.Errorf("parse contact attribs: %w", err)
	}
	return result, nil
}

// updateContactVideoAttribs merges video URLs into Contact.Attribs.
func updateContactVideoAttribs(ctx context.Context, contactID, groupID int, videoURL, thumbURL, landingURL string) error {
	// Load existing attribs
	attribs, err := loadContactAttribs(ctx, contactID, groupID)
	if err != nil {
		return err

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Read the wrapped error in the job's error column / logs to identify the root DB cause
  2. Verify the database is reachable and healthy (pg_isready, connection config in manifest/config)
  3. Confirm the bm_contacts table exists with an attribs column in the target database
  4. Check DB user permissions for SELECT on bm_contacts
  5. Retry after transient outages; consider verifying DB connectivity before launching the pipeline

Example fix

// before
val, err := g.DB().Model("bm_contacts").Ctx(ctx).Where("id", contactID).Where("group_id", groupID).Value("attribs")
// after
val, err := g.DB().Model("bm_contacts").Ctx(ctx).Timeout(10*time.Second).Where("id", contactID).Where("group_id", groupID).Value("attribs")
if err != nil {
    g.Log().Errorf(ctx, "db query bm_contacts id=%d group=%d: %v", contactID, groupID, err)
    return nil, fmt.Errorf("load contact attribs: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if err := g.DB().Ctx(ctx).Ping(ctx); err != nil {
    return fmt.Errorf("database unavailable, deferring video jobs: %w", err)
}
// then proceed with the attribs query

Try / catch

attribs, err := loadContactAttribs(ctx, job.ContactID, job.GroupID)
if err != nil {
    var dbErr interface{ IsDBError() bool }
    if errors.As(err, &dbErr) {
        // transient DB issue: leave job pending, retry next poll
        return err
    }
    markFailed(ctx, job.ID, "load_contact", err)
    return err
}

Prevention

When it happens

Trigger: The SELECT attribs FROM bm_contacts WHERE id=? AND group_id=? query returns an error: DB unreachable, connection pool exhausted, bm_contacts table missing/renamed, permission denied, or driver/timeout errors.

Common situations: PostgreSQL container down or restarting during a deploy; DATABASE_URL/DB config mispointed in staging; migration hasn't created bm_contacts in a fresh environment; transient network blips between app and DB; too many open connections under load from parallel video jobs.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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