{"record":{"id":"bc271a0788c8a189","repo":"react-navigation/react-navigation","slug":"could-not-resolve-color","errorCode":null,"errorMessage":"Could not resolve color","messagePattern":"Could not resolve color","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/native/android/src/main/java/org/reactnavigation/MaterialSymbolModule.kt","lineNumber":50,"sourceCode":"  private val fontHash: String by lazy {\n    reactApplicationContext.assets.open(\"fonts/MaterialSymbols.hash\").bufferedReader().readText()\n      .trim()\n  }\n\n  override fun getImageSource(\n    name: String, variant: String?, weight: Double?, size: Double, color: ReadableMap\n  ): String {\n    val colorValue = color.getDynamic(\"value\").let {\n      when (it.type) {\n        com.facebook.react.bridge.ReadableType.Number -> it.asDouble()\n        com.facebook.react.bridge.ReadableType.Map -> it.asMap()\n        else -> null\n      }\n    }\n\n    val resolvedColor = ColorPropConverter.getColor(\n      colorValue, currentActivity ?: reactApplicationContext\n    ) ?: throw IllegalArgumentException(\"Could not resolve color\")\n\n    val density = reactApplicationContext.resources.displayMetrics.density\n    val scaledSize = (size * density).roundToInt().coerceAtLeast(1)\n\n    val (resolvedTypeface, typefaceSuffix) = MaterialSymbolTypeface.get(\n      reactApplicationContext, variant, weight?.toInt()\n    )\n\n    val cacheDir = File(\n      reactApplicationContext.cacheDir,\n      \"react_navigation/material_symbols/$typefaceSuffix/$fontHash\"\n    )\n\n    val cacheFile = File(\n      cacheDir, \"${Uri.encode(name)}_${scaledSize}_$resolvedColor.png\"\n    )\n\n    val cacheUri = cacheFile.toUri().toString()","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/react-navigation/react-navigation/blob/ab1319d6bbf05eae8dc25e33cbf4dc56494e0f0c/packages/native/android/src/main/java/org/reactnavigation/MaterialSymbolModule.kt#L32-L68","documentation":"The MaterialSymbolModule native module resolves a color for the Material Symbols icon bitmap via ColorPropConverter.getColor(colorValue, context). When the converter returns null — the value isn't a parseable color (int/resource/known string format such as #RRGGBB or a named color) — the module throws IllegalArgumentException('Could not resolve color'). This happens on Android inside getImageSource before the icon bitmap is generated.","triggerScenarios":"Calling getImageSource (or an API that uses it, e.g. a badge/tab icon helper) with a color prop that is an unsupported value on Android: a non-hex string, an rgba()/css-style string the converter can't parse, a JS object color (platformColor object not supported here), or null/undefined reaching the converter.","commonSituations":"Passing a theme-derived color object instead of a string, using 'rgba(0,0,0,0.5)' or named colors that the Android ColorPropConverter doesn't resolve in that app's context, passing a color resource name that doesn't exist in res/values, or forgetting the color argument so undefined is forwarded.","solutions":["Pass the color as a plain hex string like '#FF0000' or '#80FF0000' (AARRGGBB) which the converter reliably parses.","If the color comes from a theme object, resolve it to a concrete string before calling (e.g. theme.colors.primary is fine, a nested object is not).","Check that any referenced Android color resource actually exists in res/values/colors.xml.","Guard the call: default to a known hex color when the value is null/undefined or not a string.","If using PlatformColor objects, convert to hex for this API since ColorPropConverter may not support them here."],"exampleFix":"// before\nconst source = await MaterialSymbol.getImageSource('home', 24, color); // color = {Qualifiers: {...}} or undefined\n// after\nconst source = await MaterialSymbol.getImageSource('home', 24, typeof color === 'string' ? color : '#000000');","handlingStrategy":"try-catch","validationCode":"const HEX_RE = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\nfunction isResolvableColor(c) {\n  return typeof c === 'string' && HEX_RE.test(c);\n}","typeGuard":"function isResolvableColor(c: unknown): c is string {\n  return typeof c === 'string' && /^#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(c);\n}","tryCatchPattern":"try {\n  const source = await MaterialSymbol.getImageSource('home', 24, color);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Could not resolve color')) {\n    // fall back to a safe default color\n    const source = await MaterialSymbol.getImageSource('home', 24, '#000000');\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always pass colors as '#RRGGBB' or '#AARRGGBB' hex strings to native icon APIs.","Resolve theme/PlatformColor objects to concrete hex strings before crossing the bridge.","Coalesce nullish color values to a default before calling getImageSource.","Verify any Android color resource referenced actually exists in res/values/colors.xml."],"tags":["react-native","android","material-symbols","color-resolution"],"backgroundTag":"could-not-resolve-color","analyzedSha":"ab1319d6bbf05eae8dc25e33cbf4dc56494e0f0c","analyzedAt":"2026-08-31T14:46:19.520Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}