🧵 PROBLEM SUMMARY: INVALID_ARGUMENT when querying campaigns via GAQL (Google Ads API v20)

🔧 Context

We’re building a Laravel controller (GoogleAccountController) to:
	•	Authenticate with Google Ads using a refresh token.
	•	List all accessible Google Ads accounts.
	•	Detect if each is an MCC or regular account.
	•	For each regular account (or child under MCC), run a GAQL query to count ENABLED campaigns.

⸻

✅ What’s Working
	•	Google Ads client is authenticated via OAuth2TokenBuilder using a valid refresh token.
	•	listAccessibleCustomers() successfully returns account resource names.
	•	For each account:
	•	We run this GAQL query successfully:

SELECT customer.descriptive_name FROM customer


	•	We correctly identify whether the account is an MCC (customer.manager = TRUE).

	•	MCCs’ child accounts are also fetched using:

SELECT customer_client.id FROM customer_client WHERE ...



⸻

❌ What’s Failing

Every attempt to query campaigns (even on non-MCC accounts) throws this error:

{
  "message": "Request contains an invalid argument.",
  "code": 3,
  "status": "INVALID_ARGUMENT"
}

GAQL Query Tried:

SELECT campaign.id FROM campaign WHERE campaign.status = ENABLED

Sample Log:

[INFO] Running GAQL on 8342244711: SELECT campaign.id FROM campaign WHERE campaign.status = ENABLED
[WARNING] Could not count campaigns for account 8342244711. {"error":"{...INVALID_ARGUMENT...}"}


⸻

🧪 Already Attempted / Verified

Check	Result
Refresh token valid	✅
Accessing correct customer_id	✅
Used loginCustomerId properly	✅
Used correct GAQL syntax	✅
MCC vs Non-MCC logic works	✅
GAQL for customer passes	✅
GAQL for campaign fails	❌
Rebuilt client per child	✅
Used GoogleAdsServiceClient	✅
Used SearchGoogleAdsRequest	✅
Also tried simpler query	❌
Tried multiple accounts	✅


⸻

🧩 Code Snippets

GAQL Campaign Query Method:

private function getCampaignCount(GoogleAdsServiceClient $adsService, string $customerId): int {
    try {
        Log::debug("Running GAQL on $customerId: SELECT campaign.id FROM campaign WHERE campaign.status = ENABLED");

        $request = new SearchGoogleAdsRequest([
            'customer_id' => $customerId,
            'query' => "SELECT campaign.id FROM campaign WHERE campaign.status = ENABLED",
            'page_size' => 1000
        ]);

        $response = $adsService->search($request);

        $count = 0;
        foreach ($response->iterateAllElements() as $row) {
            $count++;
        }

        Log::info("Account $customerId ⇒ $count enabled campaigns");
        return $count;
    } catch (\Exception $e) {
        Log::warning("Could not count campaigns for account $customerId.", ['error' => $e->getMessage()]);
        return 0;
    }
}


⸻

📌 Hypotheses
	1.	Wrong loginCustomerId context when building the client.
	•	Maybe the loginCustomerId must be set to the direct manager of the account you’re querying (not just the top MCC).
	2.	GAQL campaign access requires specific scopes or permissions that aren’t granted via the token or account link.
	3.	Customer account isn’t fully set up for campaigns yet (no campaigns = error on query instead of empty result).
	4.	Some API misbehavior or bug in v20 for campaign queries, possibly bypassable via searchStream() instead of search().

⸻

Find the permanent 100% working solution, short answer with precise fix based on code.