didi/DoKit · warning · FileNotFoundException

Last path segment is not a resource ID: " + data.uri

Error message

Last path segment is not a resource ID: " + data.uri

What it means

In Utils.getResourceId(Resources, Request), a single-segment android.resource:// URI is interpreted as a raw numeric resource ID (Integer.parseInt of the one segment). If the segment is not a number (e.g. a bare resource name like 'ic_logo'), the NumberFormatException is caught and rethrown as FileNotFoundException('Last path segment is not a resource ID: <uri>') — the single-segment form only accepts IDs, not names.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/Utils.java:348

  }

  static int getResourceId(Resources resources, Request data) throws FileNotFoundException {
    if (data.resourceId != 0 || data.uri == null) {
      return data.resourceId;
    }

    String pkg = data.uri.getAuthority();
    if (pkg == null) throw new FileNotFoundException("No package provided: " + data.uri);

    int id;
    List<String> segments = data.uri.getPathSegments();
    if (segments == null || segments.isEmpty()) {
      throw new FileNotFoundException("No path segments: " + data.uri);
    } else if (segments.size() == 1) {
      try {
        id = Integer.parseInt(segments.get(0));
      } catch (NumberFormatException e) {
        throw new FileNotFoundException("Last path segment is not a resource ID: " + data.uri);
      }
    } else if (segments.size() == 2) {
      String type = segments.get(0);
      String name = segments.get(1);

      id = resources.getIdentifier(name, type, pkg);
    } else {
      throw new FileNotFoundException("More than two path segments: " + data.uri);
    }
    return id;
  }

  static Resources getResources(Context context, Request data) throws FileNotFoundException {
    if (data.resourceId != 0 || data.uri == null) {
      return context.getResources();
    }

    String pkg = data.uri.getAuthority();

View on GitHub (pinned to 626827cddb)

Solutions

  1. Use the two-segment name form: android.resource://<package>/drawable/ic_logo.
  2. Or pass the decimal ID as a string: android.resource://<package>/2131099687 (String.valueOf(resId)).
  3. Best for local resources: pass the int directly via picasso.load(resId).

Example fix

// before
Uri uri = Uri.parse("android.resource://com.example.app/ic_logo"); // name, not ID
picasso.load(uri).into(imageView);

// after
Uri uri = Uri.parse("android.resource://com.example.app/drawable/ic_logo");
picasso.load(uri).into(imageView);
Defensive patterns

Strategy: validation

Validate before calling

Uri resourceUri(Context ctx, String type, String name) {
    return new Uri.Builder().scheme("android.resource")
        .authority(ctx.getPackageName())
        .appendPath(type).appendPath(name).build(); // 2-segment name form
}

Try / catch

Catch in error callback; the message includes the URI so mis-built segments are easy to spot in logs.

Prevention

When it happens

Trigger: Passing android.resource://com.example.app/ic_logo — a one-segment path containing a resource NAME instead of a number; passing a numeric string with whitespace or a '#'/hex prefix.

Common situations: Assuming the short form accepts names like the two-segment form does; passing Integer.toHexString(resId) or a formatted string ('res 2131099687') as the segment.

Related errors


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