Deeplinkly

Glossary/Failure modes

AASA file not found

Definition

An AASA file not found error means Apple's content delivery network could not retrieve a usable apple-app-site-association file from a domain, which disables Universal Links for that domain entirely.

The error is reported by validators and by swcutil on macOS, and it is almost never literally true — in most cases the file exists and loads fine in a browser. Apple's CDN applies constraints a browser does not: it follows no redirects, sends no credentials, and rejects the response outright if the content type is wrong. What follows is every cause, ordered by how often it turns out to be the one.

Confirm what Apple sees, not what your browser sees

Before working through the list, get the two facts that eliminate most of it. Your browser follows redirects, sends cookies, and does not care about content type, so a URL that looks healthy in a browser tells you almost nothing.

The two commands that narrow it down
# 1. What Apple's CDN holds. An empty response or a 404 here means the CDN
#    never got a usable file from your origin.
curl -sS https://app-site-association.cdn-apple.com/a/v1/example.com

# 2. What your origin returns, headers only, following redirects so you can
#    see whether there were any. You want ONE 200, and application/json.
curl -sSIL https://example.com/.well-known/apple-app-site-association
Reading the result of those two commands.
CDN responseOrigin responseWhere the problem is
Valid JSONValid JSONNot the file — see why Universal Links still fail
404 or emptySingle 200, application/jsonCDN has not fetched yet, or is holding a stale failure. Wait, or use ?mode=developer
404 or empty301 or 302 anywhere in the chainCause 1 below — redirects
404 or empty200 but Content-Type: text/htmlCause 3 below — wrong content type or an SPA catch-all
404 or empty403Cause 5 below — a WAF or bot rule
Stale contentCorrect new contentCause 9 — propagation, up to 24 hours

The nine causes, in order

1. A redirect in front of the file. Apple's CDN does not follow redirects — a 301 is a failure, not a hop. The redirects that do this are almost always ones nobody wrote deliberately: an http → https upgrade, an apex-to-www canonicalisation, a trailing-slash normaliser, or a locale prefix rewriting /.well-known/… to /en/.well-known/…. Exempt the .well-known path from every redirect rule you have.

2. The `.well-known` directory was dropped in the build. Dot-prefixed directories are excluded by default by many bundlers, static-site generators, upload tools, and Docker .dockerignore defaults. The file is in your repository, the deploy succeeds, and the directory simply is not in the artifact. Check the deployed output, not the source tree.

3. The wrong `Content-Type`, or a single-page-app catch-all. The response must be application/json. Two things commonly break this: a static server that assigns application/octet-stream to extensionless files, and an SPA or framework router that returns index.html with a 200 for any unmatched path. The second is nastier, because the URL returns 200 and looks alive while serving HTML.

4. The filename has an extension. apple-app-site-association.json is a different URL. The correct filename has no extension at all. This is common because editors add the extension on save, and because most tooling assumes JSON files end in .json.

5. A WAF, bot filter, or authentication wall. Apple's fetcher sends no cookies and no credentials, and it comes from Apple's infrastructure rather than a residential IP. Cloudflare's bot fighting mode, an enterprise WAF, HTTP basic auth on a staging domain, and Vercel's deployment protection all return 403 or a challenge page. Add an explicit allow rule for /.well-known/*.

6. The file is on a different host than the entitlement. example.com and www.example.com are distinct domains to iOS. If your entitlement says applinks:example.com but your site redirects the apex to www, cause 1 and cause 6 fire together. Host the file on both, and list both in the entitlement.

7. Invalid JSON, or valid JSON with the wrong shape. A trailing comma makes the whole file unparseable. More subtly, a file that parses but nests components one level too deep, or uses paths inside a components block, is discarded without an error. The CDN does not report shape problems — it just holds nothing.

8. The file exceeds 128 KB. Enforced as a hard cap. Above it the file is ignored in full, so every link on the domain fails simultaneously rather than degrading. Enumerated path lists are the usual cause; replace them with wildcards in components.

9. It is correct, and you are looking at a cache. Apple's CDN refreshes on its own schedule — allow up to 24 hours. Separately, the device caches the association from when the app was installed and does not re-fetch because you edited the file. Both caches have to turn over before a fix is visible.

Clearing the caches on purpose

Once the origin is serving correctly, you have three ways to stop waiting. They apply to different layers, and only the third affects real users.

What each cache-clearing method actually clears.
MethodClearsAffects
Delete and reinstall the appThe device's cached associationOnly that device
?mode=developer in the entitlementBypasses the CDN entirely for that domainDevelopment builds only — never ship it
Waiting out the CDNApple's cached copy of your fileEveryone. The only one that fixes production
Forcing and inspecting a fetch on macOS
# Force a fetch and print the reason for any failure
swcutil dl -d example.com

# Show what the system currently has associated
swcutil show --domain example.com

# Clear the local Shared Web Credentials cache, then re-fetch
sudo swcutil reset

`?mode=developer` must not ship

It makes the device fetch your domain directly on every launch, which is useful in development and wrong in production — it removes the CDN's caching and puts the request on your origin. Remove it from the entitlement before archiving a release build.

A fix that stays fixed

Six of the nine causes above are infrastructure, not application code, which means they can regress from a change nobody associated with the app: a new CDN rule, a locale router, a WAF policy update. The file passing once is not evidence it will pass next month.

  • Exempt /.well-known/* from redirects, auth, and bot rules explicitly, in configuration, with a comment saying why.
  • Add a check to CI that asserts a single 200 with Content-Type: application/json — a curl -sSI --max-redirs 0 against production catches the redirect regression on the deploy that introduces it.
  • Serve the file from both the apex and www, and list both in the entitlement, so a canonicalisation change cannot take links down.
  • Keep the file under 128 KB by using wildcards rather than enumerating paths, so the cap is never in play.

deep link debugger

Enter your domain and it runs the whole list above against the live site: the redirect chain, the content type, the size, the JSON shape, and what Apple's CDN is currently holding — plus the Android side. It reports which of the nine causes is yours rather than telling you the file is missing.

Open the deep link debugger

Frequently asked questions

Why does my AASA file load in a browser but Apple says it is not found?
A browser follows redirects, sends cookies, and ignores content type. Apple's CDN does none of those things — it requires a single 200 response with no redirects, no authentication, and a Content-Type of application/json. A file behind an http-to-https upgrade or an apex-to-www redirect loads perfectly in a browser and fails for Apple.
Does Apple follow redirects to the apple-app-site-association file?
No. Apple's CDN treats a 301 or 302 as a failure rather than following it. The request to https://yourdomain.com/.well-known/apple-app-site-association must return 200 directly. This is the single most common cause of a file that appears to be missing.
How long does it take for AASA changes to take effect?
Up to 24 hours for Apple's CDN to refresh its copy, and separately until the app is reinstalled or updated for an individual device to pick up the change. Adding ?mode=developer to the associated domains entitlement on a development build bypasses the CDN so changes are immediate, but it must be removed before release.
How do I check what Apple's CDN has for my domain?
Request https://app-site-association.cdn-apple.com/a/v1/yourdomain.com. That returns the exact copy devices are served. If it is empty or 404s while your own origin returns valid JSON, the CDN either has not fetched yet or was refused when it tried.
Why did my Universal Links break after a deploy that did not touch the app?
Most AASA failures are infrastructure rather than application code. A new redirect rule, a locale-prefix router, a WAF policy, a CDN configuration change, or a build pipeline that stops copying dot-directories will each break the file without any change to the app or to the file's contents.
Can the AASA file be served from the root of my domain instead of .well-known?
The root location is a legacy fallback from before iOS 9.3 and should not be relied on. Apple's CDN requests the .well-known path, so a new setup should serve it from https://yourdomain.com/.well-known/apple-app-site-association. Serving it at both locations is harmless.

Related terms

  • Apple App Site Association (AASA)The apple-app-site-association file is a JSON document hosted at a domain's /.well-known/ path that tells iOS which app is allowed to handle which URLs on that domain.
  • Android App Links not workingAndroid App Links fail when the system cannot verify that a domain and an app belong to the same owner, at which point tapped links open in the browser instead of the app with no error shown to the user.