material-components/material-components-android · error · IllegalArgumentException
Tab not attached to a TabLayout
Error message
Tab not attached to a TabLayout
What it means
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.
Source
Thrown at lib/java/com/google/android/material/tabs/TabLayout.java:2325
this.icon = icon;
if ((parent.tabGravity == GRAVITY_CENTER) || parent.mode == MODE_AUTO) {
parent.updateTabViews(true);
}
updateView();
return this;
}
/**
* Set the icon displayed on this tab.
*
* @param resId A resource ID referring to the icon that should be displayed
* @return The current instance for call chaining
*/
@NonNull
@CanIgnoreReturnValue
public Tab setIcon(@DrawableRes int resId) {
if (parent == null) {
throw new IllegalArgumentException("Tab not attached to a TabLayout");
}
return setIcon(AppCompatResources.getDrawable(parent.getContext(), resId));
}
/**
* Set the text displayed on this tab. Text may be truncated if there is not room to display the
* entire string.
*
* @param text The text to display
* @return The current instance for call chaining
*/
@NonNull
@CanIgnoreReturnValue
public Tab setText(@Nullable CharSequence text) {
if (TextUtils.isEmpty(contentDesc) && !TextUtils.isEmpty(text)) {
// If no content description has been set, use the text as the content description of the
// TabView. If the text is null, don't update the content description.
view.setContentDescription(text);View on GitHub (pinned to ac7e18efee)
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)).
Example fix
// before Tab tab = tabLayout.newTab().setIcon(R.drawable.ic_home); // throws tabLayout.addTab(tab); // after Tab tab = tabLayout.newTab(); tabLayout.addTab(tab); tab.setIcon(R.drawable.ic_home);
Defensive patterns
Strategy: validation
Validate before calling
// No public isAttached(): enforce order instead. Tab tab = tabLayout.newTab(); // Correct pattern: attach first, then resource-based setters. tabLayout.addTab(tab); if (resId != 0) tab.setIcon(resId);
Try / catch
try { tab.setIcon(resId); } catch (IllegalArgumentException e) { /* tab not attached yet: add it first */ tabLayout.addTab(tab); tab.setIcon(resId); } Prevention
- 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.
When it happens
Trigger: Building a tab fluently but calling setIcon(resId) before tabLayout.addTab(tab): tabLayout.newTab().setIcon(R.drawable.ic_x).setText(...), then addTab.
Common situations: Builder-style chains written before the addTab call; porting code that used the Drawable overload (which works unattached) to the resource overload.
Related errors
- Tab belongs to a different TabLayout.
- Tab does not belong to this TabLayout.
- Only TabItem instances can be added to TabLayout
- TabLayoutMediator attached before ViewPager2 has an adapter
- is not a valid TabIndicatorAnimationMode
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/1274e4b88ab09fab.
Report an issue: GitHub.