> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Manifest statuses and errors

> Fix an App Manifest that shows Unreachable, Invalid, Rejected or Out of sync, with every status, issue code, domain error and submission blocker.

Find the status, code or message the Developer Area shows for your App Manifest, and the same row gives its cause and fix. The rules for each key are in the [App Manifest reference](/docs/app-store/app-manifest/schema).

A failed check never changes the values in use. Your last good manifest keeps applying, and nothing switches back to your settings values. The one exception is `too_many_destinations`, where the check's `oauth` changes are already applied. After every fix, deploy the file and click **Check now** on the **Versions** tab.

## Statuses

The **App manifest** panel on the **Versions** tab shows one status.

| Status | Meaning | Fix |
| - | - | - |
| **Not configured** | No app domain is set. | Set your app domain on the **App details** tab. See [Connect your app domain](/docs/app-store/app-manifest#connect-your-app-domain). |
| **Up to date** | The last check succeeded and your published app matches your manifest. For an app that has never been published, `oauth` and `webhooks` are applied and `access` and `surfaces` are on your draft. | Nothing. |
| **Out of sync** | The last check succeeded. Your manifest differs from your published app in `access` or `surfaces`, a scope addition waits for review, or a webhook destination waits for a scope your app lacks. | Changed `access` or `surfaces`: click **Resubmit for review** on the **App details** tab, or change the file back. See [Changes waiting for review](#changes-waiting-for-review). Waiting destination: add the scope to `oauth.scopes`, or on the **Authentication** tab if the manifest doesn't set scopes. Then click **Check now**. |
| **Unreachable** | Fanvue couldn't read the file. The panel shows one of the reasons in [Unreachable reasons](#unreachable-reasons), and the HTTP status when there was one. Also shown if the first check after saving a domain didn't complete. | Open `https://<your app domain>/app-manifest.json` from outside your network and fix what fails. See [Serving problems](#serving-problems). |
| **Invalid** | Fanvue read the file but it failed validation. The panel lists each issue. | Fix each issue in [Validation issues](#validation-issues). |
| **Rejected** | The URL failed security checks, almost always because it returned a redirect. The panel shows the reason, for example "redirect (301) is not followed". | Retrying won't help. Serve the file directly at `https://<your app domain>/app-manifest.json` with no redirect, for example no apex to `www` or trailing-slash redirect. |

**Out of sync** doesn't block submission. An app that has never been published and has an app domain can submit only while the status is **Up to date** or **Out of sync**.

## Unreachable reasons

| Reason | Panel text | Fix |
| - | - | - |
| DNS | Your app domain didn't resolve. Check it for typos and that its DNS records are set. | Fix the domain or its DNS records. |
| TLS | Your server's HTTPS certificate couldn't be verified. | Serve a valid certificate for the exact host, with the full chain. |
| Refused | Your server refused or dropped the connection. | Check that the host accepts HTTPS on port 443 and that a firewall isn't dropping Fanvue's requests. |
| Timeout | Your server took too long to respond. | Return the whole response within 8 seconds. |
| Blocked | This URL can't be fetched because it points to a private address or includes credentials. | Point the domain at a public IP address. Private and reserved addresses are never read. |

A non-`2xx` response, or a `304` to a request without `If-None-Match`, also shows **Unreachable** with the HTTP status.

## Validation issues

Each issue shows:

* a pointer to the failing value, as a JSON Pointer such as `/oauth/redirectUris/0`; an empty pointer means the whole file
* a code
* the value you sent
* a sentence describing the problem

Checks run in two rounds. Issues that combine several fields (`conflicting_surface_url`, `fan_experience_url_on_off_platform`, `surfaces_on_off_platform`) appear only once every individual field is valid, so expect new issues after you fix the first set.

| Code | Message | Fix |
| - | - | - |
| `invalid_json` | The manifest isn't valid JSON. | Run the file through a JSON parser. Common causes: trailing commas, comments, single quotes. Save as UTF-8. |
| `invalid_content_type` | The manifest must be served with content-type application/json. | Serve it with `Content-Type: application/json` (`text/json` and `+json` types also work). |
| `manifest_too_large` | The manifest file is larger than the maximum allowed. | Keep the file under 256 KB. |
| `not_an_object` | The manifest must be a JSON object. | Wrap the file in `{ }`. An array or a bare value is rejected. |
| `nul_character` | The manifest contains a NUL character. Remove it and serve the file again. | Remove the U+0000 character. |
| `unsupported_manifest_version` | This manifest version isn't supported. | Set `"manifestVersion": 1`, a number, not the string `"1"`. |
| `unknown_key` | This key isn't part of the manifest format. | Remove the top-level key, or prefix it `x-`. Common causes: `$schema` (not supported, and no JSON Schema is published); `appName`, `tagline`, `listing` or `tracking` (set in the Developer Area, not the manifest); a top-level `postInstallUrl` (belongs in `access.postInstallUrl`). |
| `unrecognized_keys` | This object contains keys that aren't part of the manifest format. | Remove or `x-` prefix the unknown key inside the object at the pointer. Check spelling and case, for example `redirectUris`, not `redirect_uris`. |
| `sandbox_not_configurable` | Sandbox permissions are set by Fanvue and can't be declared in a manifest. | Remove `sandbox`. |
| `invalid_type` | This value is the wrong type. | Match the type in the [reference](/docs/app-store/app-manifest/schema), for example an array of objects for `webhooks.destinations`. A missing required key such as `access` also shows this code. |
| `invalid_value` | This value isn't allowed here. | Use an allowed value: check `access.type`, `surface`, `scopes`, `topic` and `presentation.type` against the reference. |
| `invalid_format` | This value isn't in the expected format. | Match the format in the reference. |
| `too_big` | This value is longer than the maximum allowed. | Shorten it. URLs are limited to 2048 characters. A dialog size is at most 1600. |
| `too_small` | This value is shorter than the minimum allowed. | A dialog size is at least 240. |
| `not_https` | This must be an https\:// URL. For a redirect URI: Only a loopback redirect URI may use http\:// | Start the URL with lowercase `https://`, with no leading space. A redirect URI may use `http://` only on `localhost`, `127.0.0.1` or `[::1]`; any other scheme, such as `javascript:` or a custom scheme, also fails with this code. |
| `invalid_url` | This must be an absolute URL. | Use a full URL including the host, for example `https://your-app.com/callback`. For a redirect URI, this code also means a username or password in the URL or a `#` fragment. |
| `wildcard_redirect_uri` | Redirect URIs can't contain wildcards. | List each redirect URI in full, with no `*`. |
| `localhost_url` | This URL can't point at localhost or a private address. | Use a public HTTPS endpoint for webhook destinations. See [URL rules](/docs/app-store/app-manifest/schema#url-rules). For local testing, use a tunnel with a public hostname. |
| `unsafe_url` | This URL was rejected for security reasons. | For webhook destinations: remove any username and password, use port 443 or 8443, and use a public host. See [URL rules](/docs/app-store/app-manifest/schema#url-rules). |
| `duplicate_surface` | Each surface can be declared only once. | Keep one entry per `surface`. |
| `duplicate_topic` | Each webhook topic can be declared only once. | Keep one destination per `topic`. |
| `conflicting_surface_url` | The access block and the surface declare different URLs for the same surface. | Make `creator_landing` `src` equal `access.url`. Make `fan_experience` `src` equal `access.fanExperienceUrl`. Or remove those entries from `surfaces`. |
| `fan_experience_url_on_off_platform` | An off-platform app can't declare a fan experience URL. | Remove `access.fanExperienceUrl`, or set `access.type` to `embedded`. |
| `surfaces_on_off_platform` | An off-platform app can't declare embedded surfaces. | Remove the `surfaces` key entirely (even `[]` fails), or set `access.type` to `embedded`. |
| `presentation_on_unsupported_surface` | Only the fan\_experience surface can declare a presentation. | Move `presentation` to the `fan_experience` entry, or remove it. |
| `dialog_size_on_page` | A page presentation can't declare a desktopWidth or desktopHeight. | Remove both sizes, or set `presentation.type` to `dialog`. |
| `incomplete_dialog_size` | Declare both desktopWidth and desktopHeight, or neither to open as large as possible. | Add the missing size, or remove the one you declared. |
| `too_many_destinations` | The manifest declares more webhook destinations than are allowed. The hint reads "This app can have at most N webhook destinations." | Remove destinations until your app is within its limit (20 by default). The count includes every destination on your app. `oauth` changes from the same check are already applied. |
| `unknown` | This value was rejected by manifest validation. | The fallback for a rule with no code of its own. Check the pointer's value against the reference. |

## Serving problems

* **Redirects.** Any `3xx` other than `304` gives **Rejected**. Common causes: a hosting provider redirecting the apex domain to `www`, or `/app-manifest.json` to a trailing-slash path. Serve the file at the exact URL, or set your app domain to the host that serves it.
* **404.** Put the file where your framework serves static files at the site root, for example `public/app-manifest.json` in Next.js.
* **Wrong content type** (status **Invalid**). Some hosts serve unknown files as `text/plain` or `application/octet-stream`. Set `Content-Type: application/json` for the path.
* **Bot protection or firewall.** Allow `GET /app-manifest.json` for the `Fanvue-App-Manifest/1` user agent.
* **Old file after deploying.** Fanvue only reads the file when you save your domain or click **Check now**. If a CDN still serves the old copy, purge it, or return an `ETag` that changes with the content.
* **`304` without an `ETag`.** Return `304 Not Modified` only when the request has `If-None-Match`. A `304` to any other request gives **Unreachable**.

To check what Fanvue will see, request the file with its user agent.

```bash theme={null}
curl -sS -D - -o /dev/null -A "Fanvue-App-Manifest/1" https://your-app.com/app-manifest.json
```

```text theme={null}
HTTP/2 200
content-type: application/json; charset=utf-8
etag: "3f1c9a"
```

## App domain errors

These messages appear under the **App domain** field on the **App details** tab.

| Message | Fix |
| - | - |
| Enter the domain without https\://, like app.example.com. | Remove `https://`. |
| Remove the path. Enter the domain only, like app.example.com. | Remove everything from the first `/`. |
| Remove everything after ? or #. Enter the domain only, like app.example.com. | Remove the query or fragment. |
| Remove the port. Your manifest is always fetched over standard https. | Remove `:port`. The manifest is always read on port 443. |
| Remove the username or password. Enter the domain only, like app.example.com. | Remove everything up to and including `@`. |
| Remove the spaces from the domain. / Remove the hidden characters from the domain. | Retype the domain. |
| Enter a domain name, not an IP address. | Use a domain name that points at your server. |
| Enter an internationalised domain in its xn-- form. | Convert the domain to punycode (`xn--…`). |
| Enter a valid domain, like app.example.com. | Use at least two labels (`your-app.com`), lowercase letters, digits and hyphens, no reserved names. See [app domain rules](/docs/app-store/app-manifest#connect-your-app-domain). |
| That domain was rejected. Use a public domain you own, like app.example.com. | The domain is a reserved name. Reserved: `localhost`, `metadata.google.internal`, the suffixes `.local`, `.internal` and `.localhost`, and the zones `test`, `invalid`, `arpa`, `onion`, `on.aws`, `fanvue.com` and `fanvue.dev`. Use a public domain you own. |
| This domain is already used by another app. Enter a different domain. | Each domain belongs to one app. Use a subdomain, for example `staging.your-app.com`. |
| Too many domain changes. Wait a minute and try again. | Wait 60 seconds. Saving a domain and **Check now** are each limited to 5 times a minute and 60 times an hour per user account, across all your apps. |

## Removing the domain

Clearing the **App domain** field and confirming **Remove domain** stops every check, and the values the manifest set go back to your settings or your live app's values. A fan experience URL stays until you remove it in **Embed settings**, and a draft that is with a reviewer isn't changed. [Removing the domain](/docs/app-store/app-manifest#removing-the-domain) lists every change.

## Submission blocked

| Message | Fix |
| - | - |
| App access: choose Off-platform or On-platform as the app type on App details and add its URL. API-only apps can't be listed | Choose a listable app type on **App details** and add its **App URL** or **Embed settings**, or declare `access` in your manifest and click **Check now**. |
| App access: your manifest couldn't be applied. Check its status on the Versions tab | The last check failed or could not be staged. Fix the status on the **Versions** tab and click **Check now**. |
| Authentication (OAuth): add a redirect URI in the Authentication tab or in your app manifest | Your app has no redirect URI in use. Add one on the **Authentication** tab, or add an entry to `oauth.redirectUris` in your manifest and click **Check now**. If the manifest has `oauth.redirectUris`, the tab's entries aren't in use. |
| Add an app URL or embed settings on App details, or declare them in your app manifest, before submitting for review. | The draft has neither an app URL nor an embed surface. Add one on **App details**, or check a manifest with `access.url`. |
| Fix your app manifest errors on the Versions tab before publishing this app for the first time. If you set an app domain, you can remove it on App details instead. | Get the status to **Up to date** or **Out of sync**. Or remove the app domain and configure the app from its settings. See [First publish with a manifest](/docs/app-store/app-manifest#first-publish-with-a-manifest). |
| This manifest removes the app's fan experience surface. Make that change in app settings, where the impact on active paid experiences is confirmed first. | Keep `access.fanExperienceUrl` in the manifest. To remove the fan experience, use **Embed settings** or switch to API-only, and confirm the paid impact there. See [Removing a fan experience](/docs/app-store/app-manifest#removing-a-fan-experience). |
| We couldn't apply your manifest. Check its status on the Versions tab and try again. | Open the **Versions** tab, fix any issue, click **Check now** and submit again. |

## Changes waiting for review

Once your app is live, changes to `access` or `surfaces` are staged onto your draft and wait for review. The **Versions** tab shows **Out of sync** with a **Changed fields** table (**Published** and **Source** columns), and the **App details** tab shows **Live · manifest changed**.

To ship them, click **Resubmit for review**. To discard them, change the file back to the published values, deploy and click **Check now**. See [Ship manifest changes to a live app](/docs/app-store/publishing-your-app#ship-manifest-changes-to-a-live-app).

Scopes added after your app is published also wait for review, whether you add them in `oauth.scopes` or on the **Authentication** tab. The **Authentication** tab shows them as **Pending review** until the submission that requests them is approved.

A webhook destination from your manifest that waits for a scope your app lacks also shows as **Out of sync**. Add the scope to `oauth.scopes` and click **Check now**.

## Symptoms in your app

| Symptom | Cause | Fix |
| - | - | - |
| Users are asked to authorise again on their next sign-in. Calls needing the new scope fail. | A scope was added to your app, from the manifest or the **Authentication** tab. That revokes every user's consent. | Expected. Send users through sign-in. See [When changes take effect](/docs/app-store/app-manifest#when-changes-take-effect). |
| API calls return `403 Forbidden` with `Insufficient scopes` | The user's token doesn't include the scope the endpoint needs. | Add the scope on the **Authentication** tab, or to `oauth.scopes` and click **Check now**. Request it in your `/oauth2/auth` URL. Have the user authorise again. |
| Sign-in fails with a redirect URI error | The `redirect_uri` your code sends isn't in the redirect URIs in use. The source in use is `oauth.redirectUris` when your manifest has that key, otherwise the **Authentication** tab. | Add the exact URI to the source in use. If the manifest sets redirect URIs, deploy the file and click **Check now**. |
| Webhook endpoints you added on the **Events** tab are marked **From manifest** | Your manifest has `webhooks.destinations`, so the file's list is in use. | Declare the endpoints in the manifest. Or remove the `webhooks` key and click **Check now** to use the tab's list. |
| The check result says "Now using your settings values for: …" | You removed a key from your manifest. That field's settings value is in use again. | Check the value on the **Authentication** or **Events** tab. An old redirect URI you no longer control can still receive OAuth redirects. Remove any you no longer use. |
| Events for a new webhook topic don't arrive | Your app lacks the topic's scope, so the destination wasn't created. | Add the scope on the **Authentication** tab, or to `oauth.scopes`. Then click **Check now**. |
| A new app URL or surface doesn't appear in your live app | `access` and `surfaces` reach a live app only after review | Click **Resubmit for review**. |

## Other messages

| Message | Fix |
| - | - |
| Manifest checked, but we couldn't apply your OAuth or webhook settings. Check again in a moment. | Click **Check now** again. |
| Your manifest changed while we were applying it. Check now, then try again. | Another check may be running for this app. Wait a moment, click **Check now**, then repeat the action. |
| Too many manifest checks. Wait a minute and try again. | Wait 60 seconds. The limit is 5 checks a minute and 60 an hour per user account. |
| Couldn't export your manifest. Please try again. | The app has no app URL yet, so there is nothing to export. Write a manifest from [Minimal manifest](/docs/app-store/app-manifest#minimal-manifest) instead. |

## See also

* [Subscribe to webhooks](/docs/webhooks/subscribing): destinations on the **Events** tab.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.