didi/DoKit · error · UnsupportedOperationException

Could not find char array in {}

Error message

Could not find char array in {}

What it means

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.

Source

Thrown at Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HahaHelper.java:136

      // In API 26, Strings are now internally represented as byte arrays.
      array = (ArrayInstance) value;

      // HACK - remove when HAHA's perflib is updated to https://goo.gl/Oe7ZwO.
      try {
        Method asRawByteArray =
            ArrayInstance.class.getDeclaredMethod("asRawByteArray", int.class, int.class);
        asRawByteArray.setAccessible(true);
        byte[] rawByteArray = (byte[]) asRawByteArray.invoke(array, 0, count);
        return new String(rawByteArray, Charset.forName("UTF-8"));
      } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
      }
    } else {
      throw new UnsupportedOperationException("Could not find char array in " + instance);
    }
  }

  public static boolean isPrimitiveWrapper(Object value) {
    if (!(value instanceof ClassInstance)) {
      return false;
    }
    return WRAPPER_TYPES.contains(((ClassInstance) value).getClassObj().getClassName());
  }

  public static boolean isPrimitiveOrWrapperArray(Object value) {
    if (!(value instanceof ArrayInstance)) {
      return false;
    }
    ArrayInstance arrayInstance = (ArrayInstance) value;
    if (arrayInstance.getArrayType() != Type.OBJECT) {
      return true;
    }

View on GitHub (pinned to 626827cddb)

Solutions

  1. Verify the value is a String instance before decoding: check class name equals 'java.lang.String'
  2. Upgrade LeakCanary / the haha perflib dependency to a version that supports the heap dump's Android version
  3. Null-check field values before calling asString (a null 'key' field takes the keysFound.add(null) path instead)

Example fix

// before
String key = HahaHelper.asString(HahaHelper.fieldValue(values, "key"));

// after
Object keyField = HahaHelper.fieldValue(values, "key");
if (keyField == null) { /* record and skip, as HeapAnalyzer does */ }
else {
  String key = HahaHelper.asString(keyField);
}
Defensive patterns

Strategy: try-catch

Validate before calling

Object v = HahaHelper.fieldValue(values, name);
if (v instanceof Instance && "java.lang.String".equals(((Instance) v).getClassObj().getClassName())) { String s = HahaHelper.asString(v); }

Try / catch

try { key = HahaHelper.asString(value); } catch (UnsupportedOperationException e) { // unexpected heap layout: record and skip this instance }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/37445e8d34bf9bf2. Report an issue: GitHub.