Skip to content

fix(pmax): make create_pmax_campaign work + add asset group linking and signals - #17

Merged
FGRibreau merged 3 commits into
FGRibreau:mainfrom
trade74:feat/pmax-asset-group-tools
Aug 19, 2026
Merged

fix(pmax): make create_pmax_campaign work + add asset group linking and signals#17
FGRibreau merged 3 commits into
FGRibreau:mainfrom
trade74:feat/pmax-asset-group-tools

Conversation

@trade74

@trade74 trade74 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

While building a real Performance Max campaign through this server I hit three blockers. Two are bugs that make create_pmax_campaign unusable; one is a missing capability without which a PMax campaign cannot serve at all.

All of it is verified end to end against a live Google Ads account (v23), not just against the test suite.

Fixed: create_pmax_campaign could not create any campaign

Every call built a plausible-looking plan and then failed at confirm_and_apply with the server's generic Request contains an invalid argument. Two independent causes:

Google error Cause
BIDDING_STRATEGY_TYPE_INCOMPATIBLE_WITH_SHARED_BUDGET campaign_budget.explicitly_shared defaults to true server-side, and PMax rejects a shared budget. draft_campaign got this fix in 5670d2d; the PMax path was missed.
fieldError=REQUIRED on contains_eu_political_advertising Required on every campaign create since the EU political ads regulation. Omitting it fails the whole mutate.

Added: link_asset_to_asset_group

upload_image_asset only ever created the asset — nothing attached it, so uploaded images sat unused in the account's asset library. A PMax asset group without a MARKETING_IMAGE, SQUARE_MARKETING_IMAGE and LOGO reports NOT_ELIGIBLE and never serves.

The field type is validated client-side against the 11 types PMax accepts, because the API error for a bad one is opaque.

Added: add_asset_group_signal

PMax does not take audiences as campaign criteria. add_audience_targeting writes a campaignCriterion userList, which the API rejects for a PMax campaign — so the server had no working way to set the single most important PMax targeting input. Signals belong on asset_group_signal.

Takes search themes, audience IDs, or both, and enforces the 80-character search theme limit before the request goes out.

Added: scripts/gads_mutate.py

None of the above was diagnosable from the server's output, which collapses Google's nested error tree to one generic string. This replays a mutate payload and prints the full tree, with --check for validateOnly. It is what surfaced all three problems.

Testing

  • 14 new unit tests (293 total, all passing); cargo clippy -D warnings and cargo fmt --check clean.
  • Verified live: a PMax campaign with an asset group, 26 text assets, 9 image assets across all five image field types, and 9 asset group signals now apply cleanly.

Two behaviours worth recording for anyone debugging PMax here, both found the hard way:

  • validateOnly does not resolve negative temp resource names when it counts an asset group's minimum assets, so a single atomic create reports false NOT_ENOUGH_HEADLINE_ASSET errors. Pre-creating the text assets and referencing real IDs validates clean.
  • With Brand Guidelines enabled on an account, BUSINESS_NAME, LOGO and LANDSCAPE_LOGO must be linked as CampaignAssets and are rejected as asset-group assets.

🤖 Generated with Claude Code

trade74 and others added 3 commits August 9, 2026 13:06
Two gaps blocked building a complete Performance Max campaign through the
server:

1. upload_image_asset created an asset but nothing linked it to an asset
   group, so images landed unattached in the asset library. A PMax asset
   group without MARKETING_IMAGE / SQUARE_MARKETING_IMAGE / LOGO is "Not
   eligible" and never serves.

2. add_audience_targeting writes a campaignCriterion userList, which the
   API rejects for a PERFORMANCE_MAX campaign. PMax audience signals and
   search themes live on asset_group_signal.

link_asset_to_asset_group validates the field type client-side against the
11 types PMax accepts, since the API error for a bad one is opaque.

add_asset_group_signal takes search themes, audience IDs, or both, and
enforces the 80-char search theme limit before the request goes out.

Both operation keys were already whitelisted in VALID_MUTATE_OPERATION_KEYS,
so no client changes were needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… script

create_pmax_campaign could not create any Performance Max campaign. Every
call built a valid-looking plan and then failed at confirm_and_apply with
"Request contains an invalid argument". Two causes:

  BIDDING_STRATEGY_TYPE_INCOMPATIBLE_WITH_SHARED_BUDGET
    campaign_budget.explicitly_shared defaults to true server-side and PMax
    rejects a shared budget. draft_campaign got this fix in 5670d2d; the
    PMax path was missed.

  fieldError=REQUIRED on contains_eu_political_advertising
    Required on every campaign create since the EU political ads
    regulation. Omitting it fails the whole mutate.

Neither was diagnosable from the server's output, which collapses Google's
error tree to a single generic string. scripts/gads_mutate.py replays a
mutate payload and prints the full tree, with --check for validateOnly.
That is what surfaced both errors, and it is worth keeping.

Verified end to end against a live account: a PMax campaign, asset group,
26 text assets, 9 image assets and 9 asset group signals now apply cleanly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@FGRibreau
FGRibreau merged commit 99ac148 into FGRibreau:main Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants