{"record":{"id":"c28fea4e97085102","repo":"JakeWharton/butterknife","slug":"bindstring-field-type-must-be-string","errorCode":null,"errorMessage":"@BindString field type must be 'String'. (","messagePattern":"@BindString field type must be 'String'\\. \\(","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"butterknife-reflect/src/main/java/butterknife/ButterKnife.java","lineNumber":653,"sourceCode":"    return Unbinder.EMPTY;\n  }\n\n  private static @Nullable Unbinder parseBindString(Object target, Field field, View source) {\n    BindString bindString = field.getAnnotation(BindString.class);\n    if (bindString == null) {\n      return null;\n    }\n    validateMember(field);\n\n    int id = bindString.value();\n    Context context = source.getContext();\n\n    Class<?> fieldType = field.getType();\n    Object value;\n    if (fieldType == String.class) {\n      value = context.getString(id);\n    } else {\n      throw new IllegalStateException(\"@BindString field type must be 'String'. (\"\n          + field.getDeclaringClass().getName()\n          + '.'\n          + field.getName()\n          + ')');\n    }\n    trySet(field, target, value);\n\n    return Unbinder.EMPTY;\n  }\n\n  private static @Nullable Unbinder parseOnCheckedChanged(final Object target, final Method method,\n      View source) {\n    OnCheckedChanged onCheckedChanged = method.getAnnotation(OnCheckedChanged.class);\n    if (onCheckedChanged == null) {\n      return null;\n    }\n    validateMember(method);\n    validateReturnType(method, void.class);","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/JakeWharton/butterknife/blob/fcdebedf3276096db2f51bf6372b849b5a9c75ed/butterknife-reflect/src/main/java/butterknife/ButterKnife.java#L635-L671","documentation":"Thrown by the reflection-based ButterKnife runtime when a field annotated with @BindString is not declared as java.lang.String. The binder calls context.getString(id) and only assigns to a String field; CharSequence, Spanned, or int fields fail the exact type check.","triggerScenarios":"ButterKnife.bind(...) via butterknife-reflect on a class with `@BindString(R.string.label) CharSequence label;` or `@BindString(R.string.label) int labelResId;`.","commonSituations":"Declaring the field as CharSequence to accept styled/Spanned strings from other code paths, or annotating a resource-id field instead of the text field. The compiler path fails the build for this; reflect defers it to runtime (frequent in unit-test setups using butterknife-reflect).","solutions":["Declare the field as `String`.","If CharSequence/Spanned is needed, bind a String field and wrap it (e.g. Html.fromHtml) afterwards.","Switch to butterknife-compiler so the mismatch is caught at compile time."],"exampleFix":"// before\n@BindString(R.string.welcome) CharSequence welcome;\n\n// after\n@BindString(R.string.welcome) String welcome;","handlingStrategy":"type-guard","validationCode":"for (Field f : targetClass.getDeclaredFields()) {\n  if (f.isAnnotationPresent(BindString.class) && f.getType() != String.class) {\n    throw new IllegalStateException(f + \" must be String\");\n  }\n}","typeGuard":"static boolean isValidBindStringField(Field f) {\n  return !f.isAnnotationPresent(BindString.class) || f.getType() == String.class;\n}","tryCatchPattern":null,"preventionTips":["Declare @BindString fields as java.lang.String (not CharSequence).","Convert to styled text after bind if needed.","Prefer butterknife-compiler for build-time validation."],"tags":["butterknife","reflection","annotation","field-type","bindstring"],"backgroundTag":null,"analyzedSha":"fcdebedf3276096db2f51bf6372b849b5a9c75ed","analyzedAt":"2026-08-14T10:13:55.083Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}