Appy
← Back to Blog
Troubleshooting

Universal Link and App Link Error Codes, Explained

SWCERR00101, SWCERR00301, legacy_failure, 1026: what each Universal Link and Android App Link error actually means, where you see it, and the fix that makes the app open again. Or let Appy’s free validator find the problem for you in seconds.

October 9, 2026•9 min read

First, make sure it is really broken

A lot of “Universal Links don’t work” reports are links behaving exactly as Apple designed them. Apple’s technote TN3155 lists the cases where the app is supposed to stay closed: a URL typed or pasted into Safari’s address bar is direct navigation, so the browser keeps it. A link to the same domain as the page you are on also stays in the browser. And third-party browsers, including the ones inside other apps, decide for themselves whether to hand a link to your app.

So test the honest way before you change a single file. Paste the link into Notes on the iPhone and long-press it. If the setup is right, the menu offers to open it in your app as well as in the browser. Whatever the user picks there becomes the default for that domain, which is another quiet reason a link that worked yesterday opens Safari today.

If Notes offers no app option, something is wrong with the association, and the error code tells you what.

The shortcut: Appy’s free validator

Before you open a terminal, paste your domain into Appy’s Universal Link validator. It fetches your apple-app-site-association file from your own server and from Apple’s CDN separately, so you see at once whether Apple has the same file you do. It also asks Google’s Digital Asset Links API what Android reads from your assetlinks.json. Free, no sign-up, one result page you can send to your developers.

If the files themselves are the problem, Appy’s AASA and assetlinks.json generator writes both from your Team ID, bundle ID and SHA-256 fingerprint. The rest of this guide explains each error, so you know exactly what to fix when the validator flags one.

Ask Apple’s CDN what it has

Since iOS 14, phones never fetch your apple-app-site-association file from your server. They get it from Apple’s CDN, which fetches it from you. So the first question is not “is my file right?” but “what does Apple have?”.

What Apple’s CDN holds for your domain

curl -sD - "https://app-site-association.cdn-apple.com/a/v1/links.example.com" -o /dev/null

A failing domain answers like this

HTTP/1.1 404 Not Found
Apple-Failure-Reason: SWCERR00101 Bad HTTP Response: 404 Not Found
Cache-Control: max-age=3600,public

Your own server, as the CDN sees it

curl -v -A "AASA-Bot/1.0" https://links.example.com/.well-known/apple-app-site-association
When we queried the CDN in October 2026, a working file came back with max-age=21600 (6 hours) and a failure with max-age=3600 (1 hour). There is no way to purge it yourself.

The SWCERR codes and what fixes them

Apple doesn’t publish a list of these codes. The ones below are the messages Apple’s CDN returns in the Apple-Failure-Reason header, each confirmed in Apple Developer Forums threads or in our own requests to the CDN.

01

SWCERR00101 · Bad HTTP Response: 404 Not Found

The CDN asked for your file and got something other than a 200. Most often the file sits on the root domain while the entitlement names a subdomain, or the other way round. Each host in applinks: needs its own file at https://that-host/.well-known/apple-app-site-association. A 502 here means your origin was down when Apple asked.

02

SWCERR00201 · Insecure (non-https) redirects forbidden

The file’s URL redirects to an http:// address. Serve it directly over HTTPS on every domain. Apple’s docs say no redirects at all; in our tests the CDN followed an https-to-https redirect, but a downgrade to http always fails.

03

SWCERR00202 · Connections to private/reserved IP addresses are not allowed

The hostname resolves to a private or reserved address, so Apple won’t connect. Typical on staging domains that only exist inside a VPN. Use developer mode for those (more below) and a public host for production.

04

SWCERR00301 · Timeout

Apple’s fetcher waited and got no headers back. Firewalls, geo-blocking and bot protection that challenge unknown clients are the usual cause. Apple says the file must be reachable from every IP and doesn’t publish its ranges, so allow the path for everyone.

05

SWCERR00302 · Network error (temporary)

A temporary failure, often DNS. If your DNS is healthy it usually clears on the next fetch, which for a failure is within the hour.

06

SWCERR00303 · TLS error

The certificate is expired, issued for a different host, self-signed, or the handshake failed. Apple needs a publicly trusted certificate that covers the exact hostname. A certificate for example.com does not cover links.example.com unless it says so.

07

SWCERR00305 · Network error

The CDN connected but the transfer broke: EOF, connection refused, or gzip: invalid header when the server claims compression it doesn’t send. Check the WAF and compression settings for that one path.

08

SWCERR00401 · Bad JSON content

The CDN got something that isn’t JSON, typically an HTML challenge page or a login page. The detail “invalid character ‘<’” gives it away. An Apple engineer’s fix in the forums: make the server return the raw file to any user agent, including AASA-Bot/*.

Check the paths with swcutil

Once Apple has the file, the next question is whether your link matches it. On a Mac, swcutil tests a local copy of the file against a real URL, which is the check Apple’s engineers recommend over developer mode.

Download test

sudo swcutil dl -d links.example.com

Match test

sudo swcutil verify -d links.example.com -j ./apple-app-site-association -u https://links.example.com/promo

What a match looks like

{ s = applinks, a = ABCD123.com.example.app, d = links.example.com }:
Pattern "https://links.example.com/promo" matched.
“blocked match” means the path is excluded on purpose, or isn’t covered by your components. Don’t mix the current appIDs + components format with the legacy appID + paths one in the same file.

What the phone itself thinks

With Developer Mode on, Settings › Developer › Universal Links has a Diagnostics screen: type a full URL and it tells you whether an installed app claims it. For the full story, take a sysdiagnose and open swcutil_show.txt. Search for your app ID and read three lines.

Site/Fmwk Approval should say approved. Unspecified or denied means the phone never received an approved file for that app and domain: check the entitlement, public access and the Team ID prefix. User Approval shows whether the person chose the browser for this domain. Last Checked and Next Check show when Apple last fetched your file.

That last point explains most “I fixed it but nothing changed” moments. After install, a phone checks the file roughly once a week. To test a fix now, reinstall the app. For staging, add ?mode=developer to the applinks entry: it skips the CDN, but only for development-signed builds on devices where you have opted in.

The numbers worth remembering

how long Apple’s CDN kept a good file in our tests
6 h

how long Apple’s CDN kept a good file in our tests

how long it kept a failure
1 h

how long it kept a failure

how often an iPhone rechecks after install
~1 week

how often an iPhone rechecks after install

Android’s minimum wait before you check verification
20 s

Android’s minimum wait before you check verification

Android App Links: the states pm get-app-links reports

Android has no CDN in the middle. The device’s verifier fetches https://your-host/.well-known/assetlinks.json itself, and since Android 12 an unverified link no longer shows a chooser: it simply opens in the browser. That is why a missing fingerprint looks exactly like “the link works, just not in my app”.

Android 12 also changed how several hosts are judged. Each host is now verified on its own; on Android 11 and lower, one host that fails verification fails all of them. And on Android 15, a change to assetlinks.json can take up to seven days to reach every device.

Re-run verification from your laptop

Reset, verify, read

adb shell pm set-app-links --package com.example.app 0 all
adb shell pm verify-app-links --re-verify com.example.app
adb shell pm get-app-links com.example.app

Typical output

example.com: verified
sub.example.com: legacy_failure
example.org: 1026
Give a fresh install at least 20 seconds before reading the result; verification runs in the background.

What each state means

01

verified

The domain passed. If links still open the browser, look at the intent filter: android:autoVerify="true", the BROWSABLE category, and both http and https schemes.

02

none

Nothing recorded yet. Wait a few minutes and run verify-app-links again.

03

legacy_failure

The legacy verifier rejected the domain without saying why. Start with the file itself: HTTP 200, application/json, HTTPS, no redirects.

04

1024 and higher (for example 1026)

A verifier-specific error. Android’s docs point at the network and the hosting: the same 200, JSON, HTTPS and no-redirect rules.

05

approved / denied

Forced by a shell command, not by verification. Reset with set-app-links before you trust any result.

06

migrated / restored / system_configured

Carried over from legacy verification, restored with user data, or set by the device configuration. Not errors, but not proof that your file works today either.

The fingerprint that is right on your laptop and wrong in the Play Store

The most common Android failure has nothing to do with hosting. With Play App Signing, Google re-signs your app with its own app signing key. The SHA-256 you get from keytool on your upload key is not the one on users’ phones, so a release build fails while your local build passes.

Copy the fingerprint from Play Console › Release › Setup › App signing instead. The sha256_cert_fingerprints array takes several values, so keep your debug key there too, in uppercase. And remember that a redirect from example.com to www.example.com, or from http to https, means Android verifies none of your links.

See what Google reads from your file

Digital Asset Links API

curl "https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls"
An empty statements list means Google couldn’t read the file: anything other than a 200, a redirect or an untrusted certificate all end up here.

Keep your campaigns running while you fix it

Broken association files shouldn’t cost you installs. An Appy link sends every phone to the right store on every plan, Huawei AppGallery included, and on Pro it tries your app first, so people who already have it land inside it. No AASA file, no SDK, no app release. When your Universal Links work again, keep the same Appy link: printed codes and posts don’t change.

appy.to/yourapp

works while you debug

  • iPhoneYour app on Pro, or the App Store
  • AndroidYour app on Pro, or Google Play
  • HuaweiAppGallery
  • ComputerYour website
Store routing on every plan, Free included. Opening the installed app on Pro, from $9.99 a month.

Read next

Error code questions

Where do I see SWCERR codes?

In the Apple-Failure-Reason header when you request https://app-site-association.cdn-apple.com/a/v1/your-domain, in swcutil dl output on a Mac, and in the swcd log on a device.

Is there a tool that checks all of this at once?

Yes. Appy’s Universal Link validator is free and needs no sign-up. It checks your AASA file on your server and on Apple’s CDN, and your assetlinks.json through Google’s Digital Asset Links API, then tells you what to fix.

How do I make Apple pick up my fixed AASA file?

You can’t purge Apple’s CDN. It refetches when its cache expires, which was one hour for failures in our tests. Then reinstall the app on your test phone so it fetches the new copy instead of waiting for the weekly check.

Is the apple-app-site-association file size limited?

Apple documented a 128 KB limit in 2016. Current docs don’t repeat it, but keeping the file small avoids the question.

Why does my link open the browser when I type it into Safari?

That is expected. Typed URLs and links within the same domain stay in the browser by design. Test from Notes or Messages instead.

What does legacy_failure mean on Android?

The legacy verifier rejected the domain and Android doesn’t say why. Check that assetlinks.json returns 200 as application/json over HTTPS with no redirects, and that it lists the Play App Signing fingerprint.

Can I avoid all of this?

Partly. On the Pro plan, an Appy link tries your app’s URL scheme first and falls back to the right store, so it works without AASA files on your own domain. Real Universal Links still need the setup above.

Continue exploring

Troubleshooting
Aug 14, 2026
10 min read

Android App Links Not Verified: A Five-Minute Diagnosis with adb

Since Android 12, an App Link that fails domain verification opens in the browser instead of your app — silently, and not on every device. The adb checklist that finds the cause fast, including the Play signing key mismatch behind most incidents.

android app links
assetlinks.json
app links verification
adb
Read article
Troubleshooting
Mar 7, 2026
11 min read

Universal Links Open Safari? Fix AASA, App Links, Redirects, and Headers

A practical troubleshooting workflow to fix universal links and app links that open the browser instead of your app.

universal links
app links
aasa
assetlinks
Read article
Guide
Oct 9, 2026
10 min read

How In-App Browsers Handle Deep Links: Instagram, TikTok, Facebook, Gmail, Telegram and More

Why a link that opens your app from Safari dies inside Instagram: the three kinds of in-app browser, the iOS and Android rules, and what each app documents, from Facebook to Telegram.

in-app browser
universal links
app links
instagram
Read article

Looking for something else? Browse all topics on the blog.

Stop losing taps to broken links

Find the broken file with the free validator, and keep every campaign working in the meantime with an Appy link: the right store on every plan, your app on Pro.