Back to Blog
Guide

Why an API Says an Account Doesn't Exist (When It Clearly Does)

October 8, 2026
9 min read
S
By SociaVault Team
API errorsInstagramTikTokFacebookYouTubetroubleshooting

Why an API Says an Account Doesn't Exist (When It Clearly Does)

You paste a handle into your script. The API comes back with "not found." You open the same profile in your browser and there it is, posting away like nothing happened.

This is the single most common error we see. In the last 60 days, 82 different API users hit a "not found" on Instagram posts, 63 on Facebook profiles and 50 on YouTube channels. Most of those accounts existed. The request just wasn't asking for them the way the platform expected.

So we tested the inputs people actually paste, one platform at a time. Here's what works, what doesn't, and how to tell a genuinely missing account from a formatting problem.

The four things "not found" can mean

Before you debug anything, know that one error message covers four very different situations:

  1. The input format is wrong. The account exists, but you sent a URL where the endpoint wanted a handle, or the reverse.
  2. The account is private. It exists, but nothing about it is public.
  3. The account was renamed. The old handle is dead. The person isn't.
  4. The account really is gone. Deleted, banned or never existed.

Only the last one is a real "doesn't exist." The first three are fixable, and the first one is by far the most common.

What each platform accepts

These are live results from the profile (or channel) endpoint for each platform, using the same well-known accounts in every format.

Instagram: handles only, @ is fine

InputResult
handle=nasaWorks
handle=@nasaWorks
handle=https://www.instagram.com/nasa/400: "You must provide a handle, not a url"

Instagram wants the bare handle. A leading @ is tolerated, a full URL is not. The error message is at least honest about it.

TikTok: no @, ever

InputResult
handle=mrbeastWorks
handle=@mrbeast400: "We just need the text, so no @ please"

This is the one that catches people moving code between platforms. Instagram and X both accept @. TikTok rejects it. If you're normalising handles once for every platform, strip the @ and you're safe everywhere.

Facebook: a full facebook.com URL

InputResult
url=https://www.facebook.com/nasaWorks
url=https://m.facebook.com/nasaWorks
url=https://www.facebook.com/NASA/Works (case and trailing slash don't matter)
url=https://fb.com/nasa400: "You must provide a valid Facebook profile URL"
url=nasa400, same message

Facebook is the reverse of Instagram. It needs a URL, and it has to be on facebook.com. The short fb.com domain that people copy from share sheets doesn't count.

YouTube: almost anything, with one catch

InputResult
handle=@mrbeastWorks
handle=mrbeastWorks
url=https://www.youtube.com/@MrBeastWorks
url=https://www.youtube.com/channel/UC...Works
channelId=UC...Works
url=https://www.youtube.com/user/LinusTechTipsWorks
url=https://www.youtube.com/c/LinusTechTipsWorks
url=https://www.youtube.com/c/MrBeast6000"Account doesn't exist"

YouTube is the most forgiving. The one failure in that table is interesting, because it isn't really a failure. That old /c/ URL returns a 404 on YouTube itself. Legacy custom URLs don't all survive channel changes, and when YouTube drops one, nothing can resolve it. If you have old /c/ links in a spreadsheet, expect a few to be dead for real. We wrote up the full set of YouTube formats in our guide to exact subscriber counts, and they apply here too.

A normaliser that fixes most of it

Since the format problem is the common one, fix it before the request goes out. This handles every rule above:

const API = "https://api.sociavault.com/v1/scrape";
const KEY = process.env.SOCIAVAULT_API_KEY;

// Turn whatever the user pasted into what each endpoint expects.
function normalise(platform, input) {
  const raw = String(input).trim();
  if (platform === "facebook") {
    // needs a full facebook.com URL; fb.com and bare names are rejected
    const path = raw
      .replace(/^https?:\/\/(www\.|m\.)?(facebook|fb)\.com\//i, "")
      .replace(/^@/, "");
    return { url: `https://www.facebook.com/${path}` };
  }
  if (platform === "youtube") {
    return /^https?:\/\//i.test(raw) ? { url: raw } : { handle: raw };
  }
  // instagram, tiktok, threads, twitter: bare handle, no @, no URL
  const handle = raw
    .replace(/^https?:\/\/(www\.)?[^/]+\//i, "") // drop the domain
    .replace(/^@/, "")
    .split(/[/?#]/)[0];
  return { handle };
}

async function lookup(platform, input) {
  const params = new URLSearchParams(normalise(platform, input));
  const path =
    platform === "youtube" ? "youtube/channel" : `${platform}/profile`;
  const res = await fetch(`${API}/${path}?${params}`, {
    headers: { "x-api-key": KEY },
  });
  const body = await res.json();
  return { status: res.status, body };
}

The Python version, same rules:

import os, re, requests

API = "https://api.sociavault.com/v1/scrape"
HEADERS = {"x-api-key": os.environ["SOCIAVAULT_API_KEY"]}

def normalise(platform, raw):
    raw = str(raw).strip()
    if platform == "facebook":
        path = re.sub(r"^https?://(www\.|m\.)?(facebook|fb)\.com/", "", raw, flags=re.I).lstrip("@")
        return {"url": f"https://www.facebook.com/{path}"}
    if platform == "youtube":
        return {"url": raw} if re.match(r"^https?://", raw, re.I) else {"handle": raw}
    handle = re.sub(r"^https?://(www\.)?[^/]+/", "", raw, flags=re.I).lstrip("@")
    return {"handle": re.split(r"[/?#]", handle)[0]}

def lookup(platform, raw):
    path = "youtube/channel" if platform == "youtube" else f"{platform}/profile"
    r = requests.get(f"{API}/{path}", params=normalise(platform, raw), headers=HEADERS, timeout=60)
    return r.status_code, r.json()

Don't trust the status code alone

Here's the gotcha that wastes the most time. When we looked up an Instagram handle that has never existed, the HTTP status was 200. The body carried the real answer:

{ "error": "Account doesn't exist" }

So a check like if (res.ok) will happily treat a missing account as a success, and you'll spend an afternoon wondering why your data has holes in it. Always look for an error field in the body, whatever the status says. We cover the wider version of this in handling errors and retries across social APIs.

A simple classifier that's served us well:

function classify({ status, body }) {
  const msg = String(body?.error ?? "").toLowerCase();
  if (status === 400) return "bad-input"; // fix the format and retry
  if (msg.includes("private")) return "private"; // exists, nothing public
  if (
    msg.includes("doesn't exist") ||
    msg.includes("not found") ||
    status === 404
  )
    return "missing";
  if (body?.error) return "other-error";
  return "ok";
}

bad-input is worth retrying after normalising. private and missing aren't. Retrying those just burns credits.

Private accounts

A private account exists, but there's nothing to fetch. Instagram, TikTok and Facebook all let users lock their profiles, and a scraper can only see what a signed-out visitor sees. Facebook is the clearest about it: private profiles come back as a 403 with "Profile is private."

LinkedIn is the odd one out. It hides a lot of profiles from signed-out visitors even when the owner has made them public, and it reports them with the same "private or not publicly available" message. That's a separate problem with its own workaround.

There's no way around a genuinely private account, and you shouldn't want one. Treat it as a final answer and move on.

Renamed accounts

Handles change all the time. Brands rebrand, creators drop the "official" suffix, people get married. If you stored the handle, your lookup now hits a dead name and reports "missing."

The fix is to store the ID next to the handle the first time you see an account. IDs don't change when the name does:

PlatformStable ID field
Instagramuser.id (numeric)
TikTokuser.id, or user.secUid
Xrest_id
YouTubechannelId (starts with UC)

On Instagram you can turn that ID back into the current handle. We looked up NASA's numeric ID through /instagram/basic-profile?userId=528817151 and got the account back, username and all. Run that when a stored handle starts failing, update your record, and carry on. For finding the right account in the first place, see how to find an official Instagram account by API.

The honest limits

  • Some "missing" accounts really are missing. Banned and deleted accounts don't come back, and no format trick changes that.
  • A dead legacy URL is dead for everyone. If YouTube itself returns a 404, so will any tool.
  • Private means private. We only fetch what's publicly visible.
  • Error wording isn't a contract. The messages quoted here are what we saw today. Match on a few keywords, as the classifier does, rather than exact strings.
  • IDs need to be captured early. If you only ever stored handles, there's no reliable way to recover an account after a rename.

Frequently Asked Questions

Why does the API say an Instagram account doesn't exist when I can see it?

Most often the input format is wrong. The Instagram endpoints want a bare handle like nasa. A full profile URL is rejected. If the format is right and it still fails, the account may have been renamed or made private.

Should I include the @ in a handle?

Leave it off. Instagram and X accept a leading @, but TikTok rejects it with a 400. Stripping it works on every platform.

The Facebook endpoints need a full facebook.com URL. The short fb.com domain and bare page names are both rejected. Rewrite fb.com/ to https://www.facebook.com/ before you send it.

Can a request return 200 and still fail?

Yes. A lookup for a nonexistent Instagram handle came back as HTTP 200 with an "Account doesn't exist" error in the body. Always check the error field, not just the status code.

How do I find an account after it's been renamed?

Use the stable ID you stored earlier. On Instagram, /instagram/basic-profile?userId= returns the account's current username. On X keep rest_id, on TikTok keep user.id, and on YouTube keep channelId.

Do failed lookups cost credits?

Credits are charged when the API returns data. Fixing the input format before you send the request is still the cheapest move, because it avoids failed calls entirely.


Want to test your own list of handles? Sign up for 50 free credits, no card needed, and run the normaliser above against the accounts that have been failing on you.

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.