Common publishing errors explained
Last updated: May 19, 2026
Common publishing errors explained
Wevion validates campaigns via apps/backend/src/services/launch-validation.service.ts (verified). Errors surface as ValidationIssue objects with code, fieldPath, message, metaErrorCode, severity. Pre-flight (POST /api/v1/campaign-drafts/:id/preflight) catches most issues before publish. Field-level validation (POST /:id/validate-field) on blur catches earlier.
Who is this for
Mediabuyers hitting validation errors in Express, Pro, or Bulk Launch. Anyone wondering "what does INVALID_AGE_RANGE actually mean".
ValidationIssue structure
Verified apps/backend/src/types/campaigns/validation.types.ts:
interface ValidationIssue {
code: string // e.g. "INVALID_AGE_RANGE"
fieldPath: string // e.g. "adSets[0].targeting.ageMin"
message: string // human-friendly description
metaErrorCode?: number // Meta API error code if from Meta side
severity: 'error' | 'warning' | 'info'
}
Errors block publish; warnings allow but flag concerns; info is informational.
Top 10 errors
1. INVALID_AGE_RANGE
fieldPath: adSets[N].targeting.ageMin or ageMax
Cause: age range out of acceptable bounds — typically ageMin < 13 (Meta minimum) OR ageMax > 65 (Meta upper bound, unless 65+).
Fix: set age range 13-65 (or 13-65+) per Meta minimum age policy. Some categories require 18+ (CREDIT/EMPLOYMENT/HOUSING — see cc-120).
2. MISSING_PIXEL
fieldPath: ads[N].conversionPixelId
Cause: campaign objective is conversion-based (Sales / Leads) but no pixel selected.
Fix: pick a pixel from the dropdown OR set up new pixel in Meta Events Manager. See meta-105 pixels and CAPI.
3. AUDIENCE_TOO_NARROW
fieldPath: adSets[N].targeting
Cause: estimated audience reach < 1.000 (platform-side minimum for delivery).
Fix: broaden audience — add countries, expand age range, remove interest layers, or use lookalike instead of narrow custom audience.
4. DSA_BENEFICIARY_REQUIRED
fieldPath: campaign.dsaBeneficiary
Cause: targeting includes EU country but DSA dsa_beneficiary field empty.
Fix: enter the legal entity benefiting from the ad (your company's legal name, or client's for agency). See cc-120 EU compliance.
5. BUDGET_BELOW_MINIMUM
fieldPath: campaign.dailyBudget or adSets[N].dailyBudget
Cause: budget below platform's minimum:
Meta: ~$1/day daily (currency-converted)
Google: ~$1/day
TikTok: ~$5/day for some objectives
Snapchat: ~$5/day
Fix: increase budget OR switch to lifetime budget with proportional duration.
6. INVALID_CTA_FOR_OBJECTIVE
fieldPath: ads[N].cta
Cause: CTA doesn't match objective (e.g. SHOP_NOW with Awareness objective).
Fix: pick CTA aligned with objective. For Sales/Leads: SHOP_NOW, SIGN_UP, BOOK_NOW. For Awareness/Traffic: LEARN_MORE, WATCH_VIDEO. See cc-115 ad copy.
7. CREATIVE_SPEC_MISMATCH
fieldPath: ads[N].creative
Cause: creative doesn't meet platform's spec (wrong aspect ratio, file too large, unsupported format).
Fix:
For aspect: re-crop or re-upload native ratio (1:1, 9:16, 16:9 per placement)
For file size: compress or split
For format: convert to JPG/PNG/WebP for images; MP4/MOV for video
8. DUPLICATE_AD_NAME
fieldPath: ads[N].name
Cause: two ads in the same campaign have the same name. Platforms require unique names.
Fix: rename one. Use versioning suffix (e.g. Ad Name v1, Ad Name v2).
9. MISSING_DESTINATION_URL
fieldPath: ads[N].destinationUrl
Cause: campaign objective requires a destination (Traffic / Sales / Leads / App) but URL field empty.
Fix: enter a valid HTTPS URL. URL must:
Be reachable (no 404)
Have HTTPS (HTTP rejected by most platforms)
Match your domain (if domain verification required by Meta for iOS 14.5+ — see meta-105)
10. SPECIAL_AD_CATEGORY_VIOLATION
fieldPath: campaign.specialAdCategory or adSets[N].targeting
Cause: special ad category set (CREDIT/EMPLOYMENT/HOUSING/SOCIAL_ISSUES) but targeting includes restricted dimensions (narrow age, ZIP for housing, certain interests).
Fix: remove the restricted targeting:
For HOUSING: no ZIP code targeting allowed
For all special categories: full age range 18-65+, gender = All
For SOCIAL_ISSUES_ELECTIONS_OR_POLITICS: complete authorized advertiser verification with Meta first
See cc-120 EU compliance + special categories.
Other common errors
Code | Cause | Fix |
|---|---|---|
| Meta campaign needs Page selected for ad source | Pick Page from dropdown (see meta-104) |
| Bid strategy incompatible with optimization goal | Pick compatible bid strategy (see cc-107 budget CBO vs ABO) |
| Selected objective doesn't exist on the chosen platform | Pick platform-supported objective (cc-106) |
| Conversion event selected but pixel doesn't report it | Verify pixel events at /pixels OR pick reported event |
| ABO with COST_CAP needs per-adset bid_amount | Provide bid_amount per ad set in Pro mode or Bulk Launch |
| Optimization goal LANDING_PAGE_VIEWS needs pixel | Pick pixel; ensure PageView event firing |
| Legacy Meta 20% text rule (deprecated 2021 but still surfaces sometimes) | Reduce text on creative or ignore the warning |
| URL has formatting issues | Verify HTTPS + valid format; no extra spaces/quotes |
| Generic Meta API error pass-through (metaErrorCode populated) | Look up Meta error code in Meta Marketing API docs |
How validation runs
Field-level (real-time)
POST /api/v1/campaign-drafts/:id/validate-field triggers on blur of each field. Inline error shown immediately. Surfaces issues like INVALID_AGE_RANGE, BUDGET_BELOW_MINIMUM as you type.
Pre-flight (before publish)
POST /api/v1/campaign-drafts/:id/preflight runs comprehensive validation. Returns ValidationResult:
{
errors: ValidationIssue[], // block publish
warnings: ValidationIssue[], // allow with confirm
info: ValidationIssue[], // informational
valid: boolean // overall pass/fail
}
If errors > 0: publish blocked. Modal shows full list with fix suggestions.
Dry-run (simulate without publishing)
POST /api/v1/campaign-drafts/:id/dry-run simulates publish via launch provider's dry_run mode. Returns what would happen without actually creating campaigns. Useful for last-mile verification.
Bulk Launch validation
Per-row + cross-row validation:
Per row: same rules as single campaign
Cross-row: duplicate campaign names within an account, conflicting bid amounts on same account, inconsistent UTM patterns
Failed rows surface in red on the grid; click row for full error detail. Fix individual rows + retry just those.
Validation severity
Severity | Behavior |
|---|---|
error | Publish blocked; must fix before continuing |
warning | Publish allowed; modal asks for explicit confirmation |
info | Just FYI; no action required |
Don't ignore warnings — they often catch suboptimal setups (audience too narrow but not blocked, creative spec might cut off, etc.).
What you'll see
In Express creative step:
Red field highlight + tooltip on error
Pre-flight summary at top of review step
In Pro mode:
Validation badge per node (campaign/adset/ad) in structure tree
Inline per-field errors
Top-bar "N errors, M warnings" summary
In Bulk Launch grid:
Per-cell red border on errors
Per-row red badge with error count
Bottom-bar "X rows, Y errors, Z warnings"
Best practices
Read the message, not just the code
Error message has the specific fix suggestion. Codes are just for tracking.
Use pre-flight before every publish
Even if no field-level errors during editing: run preflight. Catches cross-field issues.
For Bulk Launch: validate before publishing all
Toolbar "Validate all" runs full preflight on every row. Fix failures before clicking Publish all.
Build templates with known-good config
Campaign templates saved from successfully-published campaigns avoid the most-common errors automatically.
Related
Launch troubleshooting — broader post-publish issues
Publish paused vs active — pause-first catches issues pre-spend
EU compliance — DSA — DSA + special category errors