TeamNewPipe/NewPipe · warning · InvalidJsonException

JSON doesn't contain "tabs" array

Error message

JSON doesn't contain "tabs" array

What it means

Thrown by TabsJsonHelper.getTabsFromJson when the parsed top-level JSON object does not contain the "tabs" key (JSON_TABS_ARRAY_KEY). The method expects an object with a tabs array; absence of that key is treated as invalid tab configuration and raises an InvalidJsonException. Note: a null/empty input string returns default tabs instead, so this only fires for a non-empty JSON lacking the key.

Source

Thrown at app/src/main/java/org/schabi/newpipe/settings/tabs/TabsJsonHelper.java:52

     * {@link #getDefaultTabs fallback list} will be returned.
     * <p>
     * Tabs with invalid ids (i.e. not in the {@link Tab.Type} enum) will be ignored.
     *
     * @param tabsJson a JSON string got from {@link #getJsonToSave(List)}.
     * @return a list of {@link Tab tabs}.
     * @throws InvalidJsonException if the JSON string is not valid
     */
    public static List<Tab> getTabsFromJson(@Nullable final String tabsJson)
            throws InvalidJsonException {
        if (tabsJson == null || tabsJson.isEmpty()) {
            return getDefaultTabs();
        }

        try {
            final JsonObject outerJsonObject = JsonParser.object().from(tabsJson);

            if (!outerJsonObject.has(JSON_TABS_ARRAY_KEY)) {
                throw new InvalidJsonException("JSON doesn't contain \"" + JSON_TABS_ARRAY_KEY
                        + "\" array");
            }

            final JsonArray tabsArray = outerJsonObject.getArray(JSON_TABS_ARRAY_KEY, null);

            final var returnTabs = tabsArray.streamAsJsonObjects()
                    .map(Tab::from)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toUnmodifiableList());

            return returnTabs.isEmpty() ? getDefaultTabs() : returnTabs;
        } catch (final JsonParserException e) {
            throw new InvalidJsonException(e);
        }
    }

    /**
     * Get a JSON representation from a list of tabs.

View on GitHub (pinned to 9e8be09156)

Solutions

  1. Catch InvalidJsonException and fall back to getDefaultTabs() so the app still launches with sane defaults, then let the user reconfigure.
  2. Clear/reset the tabs preference to restore the default tabs JSON.
  3. Validate the JSON structure (presence of the "tabs" key) before persisting it, and write atomically to avoid truncated/corrupt saves.
  4. Add a migration step that upgrades older JSON shapes to the current {"tabs":[...]} structure.

Example fix

// before
try {
    return TabsJsonHelper.getTabsFromJson(json);
} catch (final InvalidJsonException e) {
    throw e;
}
// after
try {
    return TabsJsonHelper.getTabsFromJson(json);
} catch (final InvalidJsonException e) {
    return TabsJsonHelper.getDefaultTabs();
}
Defensive patterns

Strategy: try-catch

Validate before calling

final JsonObject obj = JsonParser.object().from(tabsJson);
if (!obj.has("tabs")) {
    // return default tabs instead of throwing
}

Try / catch

try {
    return TabsJsonHelper.getTabsFromJson(tabsJson);
} catch (final InvalidJsonException e) {
    return TabsJsonHelper.getDefaultTabs();
}

Prevention

When it happens

Trigger: getTabsFromJson is called with a non-empty JSON string whose top-level object has no "tabs" field. JsonParser.object().from succeeds (valid JSON) but outerJsonObject.has("tabs") is false.

Common situations: Corrupted or hand-edited tab settings JSON where the "tabs" key was removed or renamed, a migration/schema change that left an outdated JSON shape, or a partial write that saved a different object structure. The stored tabs preference (in SharedPreferences) got into an inconsistent state.

Related errors


AI-assisted analysis of TeamNewPipe/NewPipe@9e8be09156 (2026-08-14). Data as JSON: /api/errors/837ebcda10856972. Report an issue: GitHub.