Skip to content

Errors and exceptions

Extraction failures are checked exceptions. Everything below derives from ExtractionException (which extends Exception), so the compiler forces callers to handle them, and the type itself carries the meaning.

The hierarchy

ExtractionException
├─ ParsingException
│  ├─ ContentNotAvailableException
│  │  ├─ GeographicRestrictionException
│  │  ├─ AgeRestrictedContentException
│  │  ├─ PaidContentException
│  │  ├─ PrivateContentException
│  │  ├─ SoundCloudGoPlusContentException
│  │  ├─ YoutubeMusicPremiumContentException
│  │  ├─ AccountTerminatedException        (carries a Reason)
│  │  ├─ LiveNotStartException
│  │  └─ VideoNotReleaseException
│  ├─ ContentNotSupportedException
│  ├─ FoundAdException
│  ├─ AntiBotException
│  └─ NeedLoginException
└─ ReCaptchaException                       (carries the challenge url)

What to throw when

  • ParsingException: the page loaded but a field is missing or shaped wrong. Wrap IO and JSON failures in it.
  • ContentNotAvailableException and its subclasses: the content exists but this client cannot have it. The subclass says why, and the app maps it to a specific message:
    • GeographicRestrictionException, AgeRestrictedContentException, PaidContentException, PrivateContentException, AccountTerminatedException (with a Reason), LiveNotStartException / VideoNotReleaseException for not-yet-live and premieres, plus service-specific ones (SoundCloudGoPlusContentException, YoutubeMusicPremiumContentException).
  • ContentNotSupportedException: the extractor does not handle this kind of content, for example a channel with no supported tabs.
  • FoundAdException: the link is an ad URL; thrown straight from the link handler.
  • ReCaptchaException: the service demands a captcha; it carries the url so the app can present the challenge.

Real throw sites

YoutubeStreamExtractor inspects the player error reason and raises the right one:

java
if (message.contains("private"))      throw new PrivateContentException("This video is private");
if (reason.contains("Premieres in"))  throw new VideoNotReleaseException(reason);

SoundcloudStreamExtractor turns a "SNIP" policy into SoundCloudGoPlusContentException; YoutubeStreamLinkHandlerFactory throws FoundAdException for doubleclick hosts. This precision is what StreamInfo.getInfo relies on when it disambiguates age-restricted from country-blocked (see Extraction flow).