SOLVED Summary
You can spend too much time checking Google Cloud Console, Google Home Developer Console, OAuth redirect URIs, Home Graph API, service accounts, NGINX, port forwarding, and SSL β and every single one will look correct. The real reason Google Home fails to link after successful login and 2FA is that one single entity with an empty name or a serialization error in your HA SYNC response causes Google to silently reject the entire account linking.
One bad device name. That's it. (In my case, 5 legacy entities were added many years ago, and Google Home accepted it back in the day, but caused this issue)
The Symptoms
- Google Home app finds your Home Assistant action

- External URL reachable β
https://your-domain/auth/token returns 405 
- HA login page loads, you enter credentials and complete 2FA

- Immediately after 2FA: "Couldn't reach [your-project-name]"

- HA logs show persistent 404 errors on:
homegraph.googleapis.com/v1/devices:requestSync
homegraph.googleapis.com/v1/devices:reportStateAndNotification
- Everything in your Google and HA configuration looks correct
Why This Is So Hard To Diagnose
The 404 errors from Home Graph point you straight at Google Cloud Console. You end up checking and rechecking:
| What You Check |
Result |
| Home Graph API enabled |
Enabled |
| Service account + key |
Correct |
| OAuth consent screen |
Configured |
| Test users added |
Done |
| Authorized redirect URIs |
Sandbox |
| Actions Console account linking URLs |
Correct |
HA trusted_proxies config |
Set |
| External URL reachability |
Confirmed |
HA external_url setting |
Set |
Everything checks out. The link still fails. The 404 errors are a consequence of the failed linking β not the cause.
The Root Cause
During account linking, after OAuth completes, Google sends a SYNC intent as a POST request to your HA fulfillment URL (https://your-domain/api/google_assistant). HA responds with a single JSON document listing every exposed entity.
Google validates this entire document before registering the link. If any entity produces invalid data β an empty name, a serialization crash, a malformed attribute β Google rejects the whole document and shows "couldn't reach."
This is an all-or-nothing validation. One broken entity in 150 blocks all 150.
Culprit 1 β Entities With Empty Friendly Names
Auto-discovered devices (Daikin AC units named after their IP address, generic Tuya devices, etc.) that were never given a friendly name in HA produce this in the SYNC response:
json
"name": {"name": ""}
Google's Smart Home API spec requires name.name to be a non-empty string. One device with an empty name causes Google to reject the entire SYNC response. This single issue is enough to permanently block linking.
Culprit 2 β Yeelight Color Temperature TypeError
A bug introduced when HA updated its light attribute handling causes Yeelight color bulbs that are offline or haven't reported ATTR_MAX_COLOR_TEMP_KELVIN to crash mid-serialization:
Error serializing light.yeelight_color4_XXXXXXXX
TypeError: int() argument must be a string, a bytes-like object
or a real number, not 'NoneType'
HA catches the crash, skips the device, and sends the SYNC response anyway β but the response is now incomplete and unexpected, contributing to Google rejecting the link.
Why Did This Suddenly Start Happening?
Google tightened SYNC response validation progressively from 2023 onwards. Empty device names and incomplete attributes that were previously tolerated now cause hard rejections. A HA version update also changed how Yeelight color temperature attributes are reported, introducing the TypeError for offline or misconfigured bulbs.
Step-by-Step Diagnosis
Step 0 β Pragmatic approach - check this first:
In configuration.yaml, use expose_by_default: false (instead of true) within the google_assistant block (instead of true), restart HA, and check if you can link Google Home now.
This prevents a misconfigured legacy entity from ever reaching Google's SYNC validation
Hopefully, you can link your Google Home now. If not, carry on with the steps below:
Step 1 β Verify External Reachability First
On mobile data (not WiFi), open a browser and navigate to:
https://your-domain.com/auth/token
Expected result: 405 Method Not Allowed
This single test confirms that NGINX, port forwarding, SSL certificates, and HA are all reachable from the internet. If you get a timeout, 502, or SSL error β fix your networking before continuing. If you get 405, your infrastructure is fine and the problem is elsewhere.
Step 2 β Enable Debug Logging
Add to configuration.yaml and do a full HA restart:
yaml
logger:
default: warning
logs:
homeassistant.components.google_assistant: debug
A config reload is not enough β the logger requires a full restart to take effect.
Step 3 β Trigger a Linking Attempt and Capture Logs
Attempt to link in the Google Home app. The moment you get the "couldn't reach" error, immediately go to Settings β System β Logs in HA. (click on the 3 dots on the top right, select "show Raw logs", copy and paste it to your favourite GPT (Claude/ Gemini/ etc) to better digest the entities if required)
Step 4 β Confirm Google Is Actually Reaching HA
Search the logs for this entry:
Processing message:
{'inputs': [{'intent': 'action.devices.SYNC'}],
'requestId': 'XXXXXXXXXXXXXXXX'}
If this line exists β your connectivity, SSL, port forwarding, OAuth, and NGINX are all working correctly. Google reached HA. The problem is in the SYNC response content. Continue to Step 5.
If this line does not exist β Google never reached your fulfillment URL. Check your Actions Console fulfillment URL, HA external URL setting, and NGINX configuration.
Step 5 β Find the Broken Entities
In the same log section, look for the full SYNC response that HA built. Search for two things:
Serialization errors:
Error serializing light.yeelight_XXXXXXXX
TypeError: int() argument must be a string...not 'NoneType'
Any entity listed here is crashing during serialization.
Empty device names: Search the SYNC response output for:
'name': {'name': ''}
Even a single occurrence here means Google will reject the entire response.
The Fix
Add entity_config entries to your google_assistant: block in configuration.yaml.
Exclude entities with TypeError serialization errors:
yaml
google_assistant:
project_id: your-project-id
service_account: !include SERVICE_ACCOUNT.json
report_state: true
expose_by_default: true #IMPORTANT!! check Pragmatic Approach step 0 and change it to false for a quick check if any of your entities is causing the issue and preventing your google home to link)
entity_config:
light.yeelight_color4_XXXXXXXX_bulb1:
expose: false
light.yeelight_color4_XXXXXXXX_bulb2:
expose: false
Give names to entities with empty names:
yaml
climate.daikin_192_168_0_XXX:
name: "Living Room AC"
climate.daikin_192_168_0_YYY:
name: "Bedroom AC"
Exclude AlarmControlPanel if it has enum serialization issues:
yaml
alarm_control_panel.your_panel:
expose: false
Do a full HA restart, then retry linking in the Google Home app.
What Happens After the Fix
Once the SYNC response is clean and valid:
Google Home app completes linking successfully
Your HA devices appear in Google Home
The Home Graph 404 errors in HA logs stop automatically within minutes
requestSync and reportStateAndNotification return 200
The 404 errors were always a downstream consequence β once the SYNC succeeds and your agentUserId is registered in Google's Home Graph, all state reporting works normally without any further changes.
Preventing This in Future
- Always set a friendly name on every entity before it gets exposed to Google Assistant β especially auto-discovered climate, sensor, and media player entities
- After any HA update, check
Settings β System β Logs filtered by google_assistant for new serialization errors before re-linking
- Use
expose_by_default: false and explicitly expose only tested entities for a more controlled integration
- Use the Actions Console simulator (
Test β Simulator β type "sync my devices") to test your SYNC response quickly without going through the full Google Home app linking flow
Full Working Configuration Reference
yaml
# configuration.yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- 172.30.33.0/24 # NGINX addon network
- 172.30.32.0/24 # HA supervisor network
ip_ban_enabled: true
login_attempts_threshold: 5
google_assistant:
project_id: your-project-id
service_account: !include SERVICE_ACCOUNT.json
report_state: true
expose_by_default: true
entity_config:
light.yeelight_color4_XXXXXXXX:
expose: false
climate.daikin_192_168_0_XXX:
name: "Living Room AC"
alarm_control_panel.your_panel:
expose: false
Router port forwarding (NGINX SSL termination):
- External 443 β Internal 443 β HA host IP
Google Cloud Console:
- Home Graph API: enabled
- OAuth consent screen: External, your Google account as test user
- OAuth 2.0 Client ID (Web application), authorized redirect URIs:
https://oauth-redirect.googleusercontent.com/r/your-project-id
https://oauth-redirect-sandbox.googleusercontent.com/r/your-project-id
Google Home Developer Console account linking:
- Client ID:
https://oauth-redirect.googleusercontent.com/r/your-project-id
- Client secret: any string
- Authorization URL:
https://your-domain/auth/authorize
- Token URL:
https://your-domain/auth/token
- Fulfillment URL:
https://your-domain/api/google_assistant