Billionmail/BillionMail · error

enqueue video job: %w

Error message

enqueue video job: %w

What it means

EnqueueVideoJob inserts a pending row into the bm_video_jobs table via GoFrame's g.DB(). When the INSERT fails (connection error, missing table, constraint violation), the raw DB error is wrapped with 'enqueue video job: %w'. Note ensureTable only logs failures with g.Log().Warning — if table creation silently failed, the very next Insert fails here with 'relation "bm_video_jobs" does not exist'.

Source

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

		`)
		if err != nil {
			g.Log().Warning(ctx, "create bm_video_jobs table: ", err)
		}
	})
}

// EnqueueVideoJob inserts a pending job into bm_video_jobs.
func EnqueueVideoJob(ctx context.Context, contactID int, email string, groupID int) (int, error) {
	ensureTable(ctx)

	result, err := g.DB().Model("bm_video_jobs").Ctx(ctx).Insert(g.Map{
		"contact_id":    contactID,
		"contact_email": email,
		"group_id":      groupID,
		"status":        JobPending,
	})
	if err != nil {
		return 0, fmt.Errorf("enqueue video job: %w", err)
	}
	id, _ := result.LastInsertId()
	return int(id), nil
}

// ProcessVideoJobs polls for pending jobs and launches pipelines.
// Called by gtimer every 30s.
func ProcessVideoJobs(ctx context.Context) {
	ensureTable(ctx)

	var jobs []VideoJob
	err := g.DB().Model("bm_video_jobs").Ctx(ctx).
		Where("status", JobPending).
		OrderAsc("id").
		Limit(maxConcurrentJobs).
		Scan(&jobs)
	if err != nil {
		g.Log().Warning(ctx, "query pending video jobs: ", err)

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Read the wrapped (%w) DB error — 'relation does not exist' means run the CREATE TABLE manually or fix the ensureTable failure path.
  2. Check DB connectivity and the GoFrame DB config (host, port, user, password, database) with a direct psql connection.
  3. Grant the app DB user CREATE/INSERT privileges on the schema, or pre-create bm_video_jobs in your migration set instead of relying on ensureTable.
  4. Make ensureTable fail loudly (return an error) instead of only logging a warning, so this failure surfaces at startup.
  5. Verify search_path/schema matches between the migration and the runtime connection.

Example fix

// before
func ensureTable(ctx context.Context) {
	tableOnce.Do(func() {
		_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS bm_video_jobs (...)`)
		if err != nil {
			g.Log().Warning(ctx, "create bm_video_jobs table: ", err)
		}
	})
}
// after
// pre-create the table in a migration; at runtime fail fast on DB errors:
result, err := g.DB().Model("bm_video_jobs").Ctx(ctx).Insert(g.Map{...})
if err != nil {
	return 0, fmt.Errorf("enqueue video job: %w", err) // now wrapped error points at real DB cause
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before enqueueing: verify table exists and DB is reachable
ctxT, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if _, err := g.DB().Exec(ctxT, "SELECT 1 FROM bm_video_jobs LIMIT 1"); err != nil {
	// table missing or DB down — surface immediately instead of failing at Insert
	return fmt.Errorf("bm_video_jobs not ready: %w", err)
}

Type guard

func isMissingTable(err error) bool {
	return err != nil && strings.Contains(strings.ToLower(err.Error()), "does not exist")
}
func isConnectionError(err error) bool {
	return errors.Is(err, context.DeadlineExceeded) || strings.Contains(strings.ToLower(err.Error()), "connection refused")
}

Try / catch

jobID, err := EnqueueVideoJob(ctx, contactID, email, groupID)
if err != nil {
	switch {
	case isMissingTable(err):
		// run migration / create table explicitly, then retry once
	case isConnectionError(err):
		// check DB config/health, retry after backoff
	}
	return fmt.Errorf("enqueue video job: %w", err)
}

Prevention

When it happens

Trigger: g.DB().Model("bm_video_jobs").Insert(...) errors: DB unreachable/wrong credentials, bm_video_jobs missing because ensureTable's CREATE TABLE failed earlier, schema drift (a required column absent after a migration), or a Postgres error such as invalid input for contact_email/group_id.

Common situations: Fresh deployment where the DB user lacks CREATE privilege so ensureTable's warning was missed; Postgres down or misconfigured DSN in config; manual schema changes dropping the table; migration created the table in a different schema/search_path; connection pool exhausted under bulk enqueues from GenerateVideo.

Related errors


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