{"record":{"id":"d17da045cc0e33bb","repo":"yuliskov/SmartTube","slug":"unknown-uri-uri","errorCode":null,"errorMessage":"Unknown Uri: ${uri}","messagePattern":"Unknown Uri: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"leanbackassistant/src/main/java/com/liskovsoft/leanbackassistant/search/VideoContentProvider.java","lineNumber":118,"sourceCode":"    @Override\n    public Cursor query(\n            @NonNull Uri uri,\n            @Nullable String[] projection,\n            @Nullable String selection,\n            @Nullable String[] selectionArgs,\n            @Nullable String sortOrder) {\n\n        Log.d(TAG, uri.toString());\n\n        if (mUriMatcher.match(uri) == SEARCH_SUGGEST) {\n            Log.d(TAG, \"Search suggestions requested.\");\n\n            //String limitStr = uri.getQueryParameter(\"limit\");\n            //int limit = limitStr != null ? Integer.parseInt(limitStr) : SEARCH_LIMIT;\n            return search(uri.getLastPathSegment(), SEARCH_LIMIT);\n        } else {\n            Log.d(TAG, \"Unknown uri to query: \" + uri);\n            throw new IllegalArgumentException(\"Unknown Uri: \" + uri);\n        }\n    }\n\n    public static MediaItem findVideoWithId(int id) {\n        if (sCachedMediaItems == null) {\n            return null;\n        }\n\n        for (MediaItem video : sCachedMediaItems) {\n            if (video != null && video.getId() == id) {\n                return video;\n            }\n        }\n\n        return null;\n    }\n\n    private Cursor search(String query, int limit) {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/leanbackassistant/src/main/java/com/liskovsoft/leanbackassistant/search/VideoContentProvider.java#L100-L136","documentation":"VideoContentProvider is the read-only search-suggestions ContentProvider that feeds Android TV / Leanback global search. Its query() routes the URI through a UriMatcher that only accepts the pattern '<authority>/search/search_suggest_query/*' (authority comes from R.string.search_authority); every other URI throws IllegalArgumentException('Unknown Uri: ' + uri).","triggerScenarios":"Calling ContentResolver.query() with a URI whose authority differs from the manifest provider authority, or whose path is not /search/search_suggest_query[/<query>] — e.g. content://<authority>/videos or content://wrong.authority/search/search_suggest_query/test.","commonSituations":"The manifest authorities string or R.string.search_authority was renamed but the querying side (searchables.xml meta-data or client code) was not updated; hand-built exploratory URIs via adb shell content query; a different app targeting the provider with a stale or misspelled authority.","solutions":["Diff the incoming URI (the provider already logs it: Log.d(TAG, uri.toString())) against the expected '<authority>/search/search_suggest_query/*' pattern.","Build the query URI from the framework constant: authority + '/search/' + SearchManager.SUGGEST_URI_PATH_QUERY + '/' + query — never hand-concatenate paths.","Make sure the authority in the manifest <provider android:authorities>, the searchable.xml android:searchSuggestAuthority value, and the client code all use the identical string.","If you fork the provider and need more endpoints, add them to buildUriMatcher() instead of assuming only search exists."],"exampleFix":"// before — hand-built URI, wrong path\nUri uri = Uri.parse(\"content://\" + AUTHORITY + \"/videos\");\ngetContentResolver().query(uri, null, null, null, null); // throws Unknown Uri\n\n// after — framework search-suggest path\nUri uri = Uri.parse(\"content://\" + AUTHORITY\n        + \"/search/\" + SearchManager.SUGGEST_URI_PATH_QUERY\n        + \"/\" + Uri.encode(query));\nCursor c = getContentResolver().query(uri, null, null, null, null);","handlingStrategy":"validation","validationCode":"String SUGGEST_PATH = \"/search/\" + SearchManager.SUGGEST_URI_PATH_QUERY; // \"/search/search_suggest_query\"\n\nboolean isSearchSuggestUri(Uri uri) {\n    return uri != null\n            && AUTHORITY.equals(uri.getAuthority())\n            && uri.getPath() != null\n            && uri.getPath().startsWith(SUGGEST_PATH);\n}\n\n// use\nUri uri = Uri.parse(\"content://\" + AUTHORITY + SUGGEST_PATH + \"/\" + Uri.encode(q));\nif (isSearchSuggestUri(uri)) {\n    Cursor c = getContentResolver().query(uri, null, null, null, null);\n}","typeGuard":null,"tryCatchPattern":"try {\n    Cursor c = getContentResolver().query(uri, null, null, null, null);\n} catch (IllegalArgumentException e) { // Unknown Uri\n    Log.w(TAG, \"Bad provider URI: \" + uri, e);\n    // skip gracefully — never retry the same URI unchanged\n}","preventionTips":["Build suggestion URIs only from the constant path '/search/' + SearchManager.SUGGEST_URI_PATH_QUERY.","Keep manifest android:authorities, searchable.xml and client strings identical — define the authority once.","Use adb shell content query --uri content://<authority>/search/search_suggest_query/test to smoke-test before shipping."],"tags":["android","content-provider","uri","search","android-tv"],"backgroundTag":"content-provider-uri-mismatch","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}