{"record":{"id":"1274e4b88ab09fab","repo":"material-components/material-components-android","slug":"tab-not-attached-to-a-tablayout","errorCode":null,"errorMessage":"Tab not attached to a TabLayout","messagePattern":"Tab not attached to a TabLayout","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/tabs/TabLayout.java","lineNumber":2325,"sourceCode":"      this.icon = icon;\n      if ((parent.tabGravity == GRAVITY_CENTER) || parent.mode == MODE_AUTO) {\n        parent.updateTabViews(true);\n      }\n      updateView();\n      return this;\n    }\n\n    /**\n     * Set the icon displayed on this tab.\n     *\n     * @param resId A resource ID referring to the icon that should be displayed\n     * @return The current instance for call chaining\n     */\n    @NonNull\n    @CanIgnoreReturnValue\n    public Tab setIcon(@DrawableRes int resId) {\n      if (parent == null) {\n        throw new IllegalArgumentException(\"Tab not attached to a TabLayout\");\n      }\n      return setIcon(AppCompatResources.getDrawable(parent.getContext(), resId));\n    }\n\n    /**\n     * Set the text displayed on this tab. Text may be truncated if there is not room to display the\n     * entire string.\n     *\n     * @param text The text to display\n     * @return The current instance for call chaining\n     */\n    @NonNull\n    @CanIgnoreReturnValue\n    public Tab setText(@Nullable CharSequence text) {\n      if (TextUtils.isEmpty(contentDesc) && !TextUtils.isEmpty(text)) {\n        // If no content description has been set, use the text as the content description of the\n        // TabView. If the text is null, don't update the content description.\n        view.setContentDescription(text);","sourceCodeStart":2307,"sourceCodeEnd":2343,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/tabs/TabLayout.java#L2307-L2343","documentation":"Tab.setIcon(@DrawableRes int) needs the owning TabLayout to resolve the resource, so it requires tab.parent != null (set only when the tab is added via addTab). Calling it on a tab created by newTab() but not yet added throws IllegalArgumentException.","triggerScenarios":"Building a tab fluently but calling setIcon(resId) before tabLayout.addTab(tab): tabLayout.newTab().setIcon(R.drawable.ic_x).setText(...), then addTab.","commonSituations":"Builder-style chains written before the addTab call; porting code that used the Drawable overload (which works unattached) to the resource overload.","solutions":["Reorder so addTab(tab) happens before setIcon(resId).","Or use the Drawable overload, which does not need the parent: setIcon(AppCompatResources.getDrawable(context, resId))."],"exampleFix":"// before\nTab tab = tabLayout.newTab().setIcon(R.drawable.ic_home); // throws\n tabLayout.addTab(tab);\n\n// after\nTab tab = tabLayout.newTab();\ntabLayout.addTab(tab);\ntab.setIcon(R.drawable.ic_home);","handlingStrategy":"validation","validationCode":"// No public isAttached(): enforce order instead.\nTab tab = tabLayout.newTab();\n// Correct pattern: attach first, then resource-based setters.\ntabLayout.addTab(tab);\nif (resId != 0) tab.setIcon(resId);","typeGuard":null,"tryCatchPattern":"try { tab.setIcon(resId); } catch (IllegalArgumentException e) { /* tab not attached yet: add it first */ tabLayout.addTab(tab); tab.setIcon(resId); }","preventionTips":["Always addTab() before resource-based setters (setIcon/setText/contentDescription with resId).","Prefer Drawable/CharSequence overloads during pre-attachment setup.","Wrap tab construction in one helper that attaches first."],"tags":["tablayout","tabs","api-order","android"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}