{"record":{"id":"37445e8d34bf9bf2","repo":"didi/DoKit","slug":"could-not-find-char-array-in","errorCode":null,"errorMessage":"Could not find char array in {}","messagePattern":"Could not find char array in (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HahaHelper.java","lineNumber":136,"sourceCode":"      // In API 26, Strings are now internally represented as byte arrays.\n      array = (ArrayInstance) value;\n\n      // HACK - remove when HAHA's perflib is updated to https://goo.gl/Oe7ZwO.\n      try {\n        Method asRawByteArray =\n            ArrayInstance.class.getDeclaredMethod(\"asRawByteArray\", int.class, int.class);\n        asRawByteArray.setAccessible(true);\n        byte[] rawByteArray = (byte[]) asRawByteArray.invoke(array, 0, count);\n        return new String(rawByteArray, Charset.forName(\"UTF-8\"));\n      } catch (NoSuchMethodException e) {\n        throw new RuntimeException(e);\n      } catch (IllegalAccessException e) {\n        throw new RuntimeException(e);\n      } catch (InvocationTargetException e) {\n        throw new RuntimeException(e);\n      }\n    } else {\n      throw new UnsupportedOperationException(\"Could not find char array in \" + instance);\n    }\n  }\n\n  public static boolean isPrimitiveWrapper(Object value) {\n    if (!(value instanceof ClassInstance)) {\n      return false;\n    }\n    return WRAPPER_TYPES.contains(((ClassInstance) value).getClassObj().getClassName());\n  }\n\n  public static boolean isPrimitiveOrWrapperArray(Object value) {\n    if (!(value instanceof ArrayInstance)) {\n      return false;\n    }\n    ArrayInstance arrayInstance = (ArrayInstance) value;\n    if (arrayInstance.getArrayType() != Type.OBJECT) {\n      return true;\n    }","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HahaHelper.java#L118-L154","documentation":"HahaHelper.asString() decodes a String instance from a parsed heap dump (haha/perflib model). It expects either a direct char[]-backed java.lang.String or (on newer Android versions) a byte[]-backed String with a compact-strings encoding, which it reads reflectively via ArrayInstance.asRawByteArray. If the instance is neither shape, it throws UnsupportedOperationException because it cannot decode the value.","triggerScenarios":"Calling HahaHelper.asString(instance) where instance is not a java.lang.String ClassInstance from the heap snapshot — e.g. passing a Type, ClassObj, ArrayInstance of the wrong type, or a String whose value field layout does not match what the helper looks for. Happens when heap dumps from newer Android versions (byte-backed strings, ART string layout changes) are parsed by an older haha parser that cannot find the char[] 'value' field.","commonSituations":"Analyzing a heap dump captured on a recent Android version with an old LeakCanary/haha version bundled in DoraemonKit. Passing KeyedWeakReference field values (e.g. the 'key' field) that resolved to null or a non-string array.","solutions":["Verify the value is a String instance before decoding: check class name equals 'java.lang.String'","Upgrade LeakCanary / the haha perflib dependency to a version that supports the heap dump's Android version","Null-check field values before calling asString (a null 'key' field takes the keysFound.add(null) path instead)"],"exampleFix":"// before\nString key = HahaHelper.asString(HahaHelper.fieldValue(values, \"key\"));\n\n// after\nObject keyField = HahaHelper.fieldValue(values, \"key\");\nif (keyField == null) { /* record and skip, as HeapAnalyzer does */ }\nelse {\n  String key = HahaHelper.asString(keyField);\n}","handlingStrategy":"try-catch","validationCode":"Object v = HahaHelper.fieldValue(values, name);\nif (v instanceof Instance && \"java.lang.String\".equals(((Instance) v).getClassObj().getClassName())) { String s = HahaHelper.asString(v); }","typeGuard":null,"tryCatchPattern":"try { key = HahaHelper.asString(value); } catch (UnsupportedOperationException e) { // unexpected heap layout: record and skip this instance }","preventionTips":["Null-check and type-check field values before decoding","Keep the LeakCanary/haha parser version aligned with the Android versions you capture dumps from"],"tags":["leakcanary","heap-dump","android","haha","java"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}