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:
- Self-host Piped-Backend without setting
GEO_RESTRICTION_CHECKER_URL in config
- Request a video that is geo-restricted in your region via the API:
/streams/{videoId}
- Observe the response contains:
"This instance does not have a geo restriction checker set in its configuration"
Bug 2:
- Configure Piped-Backend with both
MATRIX_TOKEN and GEO_RESTRICTION_CHECKER_URL
- Request a video where the extractor throws
GeographicRestrictionException (false positive geo-detection)
- The configured restriction checker correctly returns
{ "restricted": false }
- 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
Official Instance
The primary bug (misleading error message) only affects self-hosted instances without
GEO_RESTRICTION_CHECKER_URLconfigured. The secondary bug (NPE risk) can affect instances that DO have bothMATRIX_TOKENandGEO_RESTRICTION_CHECKER_URLconfigured.Describe the bug
There are two related issues in
StreamHandlers.javain the geo-restriction handling block:Bug 1: Misleading error message for self-hosted instances
When a video causes
NewPipeExtractorto throwGeographicRestrictionException, the lambda at line ~56 catches it and returnsnull(not re-throws), soexceptionstaysnullandinfoisnull.The code path then reaches:
This message is misleading for self-hosted users because:
GEO_RESTRICTION_CHECKER_URLis not configured by default and is not expected to be set on private self-hosted instancesA clearer message would be:
"This video is geo-restricted and is not available in your region".Bug 2: NullPointerException when restriction checker returns
restricted: falseWhen both
MATRIX_TOKENandGEO_RESTRICTION_CHECKER_URLare 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:Since the extractor's
GeographicRestrictionExceptionwas caught inside the lambda (which returnednullinstead of propagating),exceptionis alwaysnullin this code path. In production (where assert is disabled),throw (Exception) nullthrows aNullPointerExceptioninstead of a meaningful error.To Reproduce
Bug 1:
GEO_RESTRICTION_CHECKER_URLin config/streams/{videoId}"This instance does not have a geo restriction checker set in its configuration"Bug 2:
MATRIX_TOKENandGEO_RESTRICTION_CHECKER_URLGeographicRestrictionException(false positive geo-detection){ "restricted": false }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:
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. Sinceexceptioncan benullin this path, a safe check is needed:Logs/Errors
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:56catchesGeographicRestrictionExceptionand returnsnull:This means
info == nullandexception == null. The subsequent checkelse 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