Skip to content

Reference

Troubleshooting

The ten most common ways universal links and Android App Links break, what causes each one, how to fix it, and the rndl diagnostic code that catches it.

The ten most common ways universal links and Android App Links break, what causes each one, and how to fix it. Where rndl validate catches the problem, the diagnostic code is listed so you can find it in the output. A few footguns live in your app's native config (entitlements, the manifest); rndl validates the domain side and the route table, so those are flagged here as manual checks.

Prefer the long-form version? The deep dive Why universal links and Android App Links break walks through the same ten failures with the platform behavior behind each one.

1. The AASA file is behind a redirect

Symptom: the link opens Safari, not your app, even though the file looks correct.

Cause: Apple fetches apple-app-site-association with redirects disabled. A 301/302 (often an apex-to-www redirect, or an auth wall) means Apple sees no file at all.

Fix: serve the file with a 200 at the exact URL, no redirect. Check both the apex and any www host you advertise.

rndl: AASA_REDIRECTED (error). The assetlinks equivalent is ASSETLINKS_REDIRECTED.

2. The AASA file is not reachable over plain HTTPS

Symptom: validation cannot fetch the file.

Cause: it is served over HTTP, blocked by auth, or missing. The file must live at https://<domain>/.well-known/apple-app-site-association (no .json extension) and return 200.

Fix: put it under /.well-known/, HTTPS, publicly reachable, no extension.

rndl: AASA_NOT_HTTPS, AASA_FETCH_FAILED.

3. The AASA file has the wrong Content-Type

Symptom: iOS ignores an otherwise valid file.

Cause: it is served as text/html or text/plain. Apple expects application/json (and does not require, but tolerates, the file having no extension).

Fix: serve apple-app-site-association as application/json.

rndl: AASA_CONTENT_TYPE (warning).

4. The AASA file is too large

Symptom: iOS silently drops your associations.

Cause: the file exceeds Apple's 128KB limit, usually from thousands of components.

Fix: collapse patterns; prefer a small number of wildcarded components over one per route.

rndl: AASA_TOO_LARGE (error).

5. The appID (Team ID + bundle ID) is missing or wrong

Symptom: links do not open even though the domain resolves.

Cause: applinks.details[].appIDs (or the legacy appID) must be <TeamID>.<BundleID>. A typo, a wildcard, or the wrong team breaks the association.

Fix: use the exact TEAMID.com.your.bundle. Find the Team ID in your Apple Developer account.

rndl: AASA_MISSING_APPID, AASA_INVALID_APPID.

6. A route is not covered by any component (or a component covers nothing)

Symptom: some links open the app but land on the wrong screen, or a marketing path never opens the app at all.

Cause: the components in your AASA do not line up with the routes your app actually declares.

Fix: run the cross-check from your app directory so rndl compares the two. Add a component for every route you want to be a universal link, and remove components that match nothing.

rndl: AASA_MISSING_ROUTE (error), AASA_ORPHAN_PATTERN (warning). Needs --app-dir/--config (auto-detected in an app directory).

Symptom: everything on the server is correct, but links still open Safari.

Cause: the Associated Domains entitlement entry must read applinks:example.com, not example.com. This lives in your app (Xcode Signing and Capabilities, or app.json ios.associatedDomains), so the server-side file cannot reveal it.

Fix: add applinks:<domain> for every host, rebuild, and reinstall. ?mode=developer on the entitlement bypasses Apple's CDN cache while testing.

rndl: not detected (app-side). Check your entitlements or app.json.

8. The Android signing fingerprint does not match

Symptom: App Links verify on a debug build but fail after release (or vice versa).

Cause: assetlinks.json lists a sha256_cert_fingerprints value from a different keystore than the installed build. Debug and release (and Play App Signing) each have their own fingerprint.

Fix: include every fingerprint you ship with, including Google Play's app-signing certificate. Pass --sha256 <fingerprint> to confirm a specific one is present.

rndl: ASSETLINKS_FINGERPRINT_MISMATCH, ASSETLINKS_INVALID_FINGERPRINT, ASSETLINKS_NO_FINGERPRINTS.

9. The Android package name or relation is wrong

Symptom: Android never verifies the domain.

Cause: assetlinks.json has the wrong package_name, or its relation is not delegate_permission/common.handle_all_urls.

Fix: set package_name to your applicationId and use the exact relation string. Pass --package <name> (or let rndl read it from app.json) to check it.

rndl: ASSETLINKS_PACKAGE_MISMATCH, ASSETLINKS_PACKAGE_MISSING, ASSETLINKS_NO_HANDLE_ALL_URLS, ASSETLINKS_INVALID_RELATION.

10. The Android manifest is missing autoVerify or the right intent filter

Symptom: assetlinks.json is perfect, but tapping a link shows the app chooser instead of opening your app directly.

Cause: the <intent-filter> for your https host needs android:autoVerify="true", plus the VIEW action, BROWSABLE category, and matching scheme/host data. This lives in your AndroidManifest.xml (or app.json android.intentFilters), not on the server.

Fix: add autoVerify and the intent filter, rebuild, and verify with adb shell pm get-app-links <package>.

rndl: not detected (app-side). Check your manifest or app.json.

A note on caching and propagation

Apple serves AASA through a CDN, so changes can take 24 hours or more to reach devices (a first-time fetch can take days); use ?mode=developer on the entitlement while testing, and reinstall the app to force a re-fetch. Android re-verifies App Links on install and on update. rndl validate surfaces the caching note in its output and never treats a fresh change as a hard failure.