Billionmail/BillionMail · error

contact %d missing website_url

Error message

contact %d missing website_url

What it means

RunPipeline validates that the contact's attribs map contains a non-empty website_url before proceeding with screenshot capture. The video generation pipeline (screenshots, script, landing page) is built around the contact's website, so without website_url the job cannot proceed. The error is raised after loadContactAttribs succeeded, meaning the contact row exists and has attribs, but the attribs JSON lacks the website_url key or has it set to an empty string.

Source

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

	g.Log().Infof(ctx, "video job %d starting pipeline for contact %d <%s>", job.ID, job.ContactID, job.ContactEmail)
	tmpDir := fmt.Sprintf("/tmp/video_gen_%d", job.ID)
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		markFailed(ctx, job.ID, "setup", err)
		return err
	}

	// 1. Load contact attribs
	attribs, err := loadContactAttribs(ctx, job.ContactID, job.GroupID)
	if err != nil {
		markFailed(ctx, job.ID, "load_contact", err)
		return err
	}

	websiteURL := attribs["website_url"]
	businessName := attribs["business_name"]
	ownerName := attribs["owner_name"]
	if websiteURL == "" {
		err = fmt.Errorf("contact %d missing website_url", job.ContactID)
		markFailed(ctx, job.ID, "load_contact", err)
		return err
	}

	// Parse signals
	signals := parseSignals(attribs["lead_signals"])

	// 2. Screenshots + Annotate
	updateJobStatus(ctx, job.ID, JobProcessing, "screenshot", "")
	screenshots, err := withRetry(func() (*ScreenshotResult, error) {
		return CaptureScreenshots(ctx, DefaultScreenshotConfig(websiteURL, businessName, tmpDir))
	})
	if err != nil {
		markFailed(ctx, job.ID, "screenshot", err)
		return err
	}

	updateJobStatus(ctx, job.ID, JobProcessing, "annotate", "")

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check the contact row in bm_contacts (SELECT attribs FROM bm_contacts WHERE id=<contactID> AND group_id=<groupID>) and confirm website_url exists and is non-empty
  2. Fix the import/enrichment process so website_url is always populated before enqueuing video jobs
  3. Add a pre-enqueue guard in EnqueueVideoJob or the caller that validates attribs["website_url"] != "" and skips/fails the contact early instead of consuming a pipeline slot
  4. If the website is genuinely unknown, exclude such contacts from video generation campaigns

Example fix

// before
result, err := EnqueueVideoJob(ctx, contact.ID, contact.Email, groupID)
// after
attribs, _ := loadContactAttribs(ctx, contact.ID, groupID)
if attribs["website_url"] == "" {
    return fmt.Errorf("skip contact %d: no website_url", contact.ID)
}
result, err := EnqueueVideoJob(ctx, contact.ID, contact.Email, groupID)
Defensive patterns

Strategy: validation

Validate before calling

attribs, err := loadContactAttribs(ctx, contactID, groupID)
if err != nil { return err }
if strings.TrimSpace(attribs["website_url"]) == "" {
    return fmt.Errorf("contact %d has no website_url; not eligible for video generation", contactID)
}

Try / catch

if err := RunPipeline(ctx, job); err != nil {
    var missing *MissingFieldError
    if errors.As(err, &missing) && missing.Field == "website_url" {
        // skip this contact permanently, don't retry
        skipContact(job.ContactID, "no website_url")
    }
}

Prevention

When it happens

Trigger: RunPipeline calls loadContactAttribs(contactID, groupID), gets a valid map, but attribs["website_url"] is empty — i.e. the bm_contacts.attribs JSON either omits the website_url field or stores "".

Common situations: Contacts imported via CSV/Excel without the website_url column mapped; contacts created manually by users who skipped the website field; upstream enrichment jobs that failed silently and wrote attribs without website_url; leads sourced from channels (e.g. Google Maps scraping) where the website was not present on the source record.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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