Skip to content

StreamHandlers: misleading GeographicRestrictionException message for self-hosted instances + potential NPE when exception is null #4250

Description

@jollySleeper

Official Instance

The primary bug (misleading error message) only affects self-hosted instances without GEO_RESTRICTION_CHECKER_URL configured. The secondary bug (NPE risk) can affect instances that DO have both MATRIX_TOKEN and GEO_RESTRICTION_CHECKER_URL configured.

Describe the bug

There are two related issues in StreamHandlers.java in the geo-restriction handling block:


Bug 1: Misleading error message for self-hosted instances

When a video causes NewPipeExtractor to throw GeographicRestrictionException, the lambda at line ~56 catches it and returns null (not re-throws), so exception stays null and info is null.

The code path then reaches:

} else if (Constants.GEO_RESTRICTION_CHECKER_URL == null) {
    throw new GeographicRestrictionException("This instance does not have a geo restriction checker set in its configuration");
}

This message is misleading for self-hosted users because:

  • It implies a configuration problem on the instance owner's side
  • The real reason is that the video is geo-restricted in the user's region
  • GEO_RESTRICTION_CHECKER_URL is not configured by default and is not expected to be set on private self-hosted instances
  • Users/clients have no idea what a "geo restriction checker" is or that they need one

A clearer message would be: "This video is geo-restricted and is not available in your region".


Bug 2: NullPointerException when restriction checker returns restricted: false

When both MATRIX_TOKEN and GEO_RESTRICTION_CHECKER_URL are configured, and the restriction checker responds with { "restricted": false } (i.e., the extractor's geo-detection was a false positive), the following code is reached:

if (!restrictedTree.get("restricted").asBoolean()) {
    assert exception != null;
    throw (Exception) exception;  // ← exception is null here!
}

Since the extractor's GeographicRestrictionException was caught inside the lambda (which returned null instead of propagating), exception is always null in this code path. In production (where assert is disabled), throw (Exception) null throws a NullPointerException instead of a meaningful error.

To Reproduce

Bug 1:

  1. Self-host Piped-Backend without setting GEO_RESTRICTION_CHECKER_URL in config
  2. Request a video that is geo-restricted in your region via the API: /streams/{videoId}
  3. Observe the response contains: "This instance does not have a geo restriction checker set in its configuration"

Bug 2:

  1. Configure Piped-Backend with both MATRIX_TOKEN and GEO_RESTRICTION_CHECKER_URL
  2. Request a video where the extractor throws GeographicRestrictionException (false positive geo-detection)
  3. The configured restriction checker correctly returns { "restricted": false }
  4. Observe a NullPointerException (instead of the original exception being re-thrown)

Expected behavior

Bug 1: The error message should clearly communicate that the video is geo-restricted in the user's region, not that the instance is misconfigured.

Suggested fix:

} else if (Constants.GEO_RESTRICTION_CHECKER_URL == null) {
    throw new GeographicRestrictionException("This video is geo-restricted and is not available in your region");
}

Bug 2: When the restriction checker returns restricted: false (extractor false positive), the code should either re-throw the original exception safely or return a proper error — not NPE. Since exception can be null in this path, a safe check is needed:

if (!restrictedTree.get("restricted").asBoolean()) {
    if (exception != null)
        throw (Exception) exception;
    throw new GeographicRestrictionException("Video could not be extracted (geo-detection false positive)");
}

Logs/Errors

org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException: This instance does not have a geo restriction checker set in its configuration
	at me.kavin.piped.server.handlers.StreamHandlers.streamsResponse(StreamHandlers.java:234)
	at me.kavin.piped.server.ServerLauncher.lambda$mainServlet$10(ServerLauncher.java:113)
	at io.activej.http.AsyncServlet.lambda$ofBlocking$0(AsyncServlet.java:43)
	at io.activej.promise.Promise.lambda$ofBlocking$12(Promise.java:249)
	at java.base/java.util.concurrent.ThreadPerTaskExecutor$TaskRunner.run(ThreadPerTaskExecutor.java:314)
	at java.base/java.lang.VirtualThread.run(VirtualThread.java:329)

Browser, and OS with Version.

N/A — this is a backend API issue. Observed with NewPipeExtractor v0.26.3 (upstream) on a self-hosted Piped-Backend instance.

Additional context

Root cause trace for Bug 1:

The lambda at StreamHandlers.java:56 catches GeographicRestrictionException and returns null:

} catch (Exception e) {
    if (e instanceof GeographicRestrictionException) {
        return null; // info = null, exception stays null
    }
    ExceptionUtils.rethrow(e);
}

This means info == null and exception == null. The subsequent check else if (GEO_RESTRICTION_CHECKER_URL == null) fires correctly, but the error message conflates a content restriction with an instance configuration problem.

Affected code: me.kavin.piped.server.handlers.StreamHandlers.streamsResponse, lines ~233–240

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions