sdk-for-android icon indicating copy to clipboard operation
sdk-for-android copied to clipboard

🐛 Bug Report: Getting java.lang.NullPointerException when using Query.select on attributes along with limit query

Open bigraymasoom opened this issue 1 year ago • 1 comments

👟 Reproduction steps

  1. Call the listDocuments function with parameters that include database and collection IDs, a numeric limit, and a list of attributes.
  2. Include attribute selection in the query, where attribute names are passed dynamically to the Query.select method.
  3. Execute the function, which internally calls toJson() on the Query object.

👍 Expected behavior

Expected Behavior: The function should handle null values gracefully and not attempt to cast nulls to non-null strings. If a parameter is null, it should either be managed by default values or handled with appropriate error messages.

👎 Actual Behavior

Actual Behavior: The application throws a java.lang.NullPointerException: null cannot be cast to non-null type kotlin.String during the execution of the toJson() method in the Query class. This error suggests that there might be issues with how null values are being managed within query parameters or during their serialization/deserialization process.

🎲 Appwrite version

Version 1.5.x

💻 Operating system

Linux

🧱 Your Environment

No response

👀 Have you spent some time to check if this issue has been raised before?

  • [X] I checked and didn't find similar issue

🏢 Have you read the Code of Conduct?

bigraymasoom avatar Jul 10 '24 20:07 bigraymasoom

Android SDK version I am using is 5.1.1

bigraymasoom avatar Jul 10 '24 20:07 bigraymasoom

@bigraymasoom Thanks for raising this issue. Sorry about taking this long. The team will verify if the issue still persists and get back to this 👍

ChiragAgg5k avatar May 02 '25 13:05 ChiragAgg5k

Thanks, will surely wait for this. If its implemented i will be able to just get data for specific attributes in android instead of getting the whole data and the filtering the required one.

bigraymasoom avatar May 02 '25 16:05 bigraymasoom

@ChiragAgg5k This is my complete discussion with gemini on this matter

Thank you for providing the source code for the Query class. This is the final piece of the puzzle, and it allows for a definitive explanation of everything we've observed.

After analyzing this code, my previous conclusion is strongly reinforced. Let's break down what this code reveals.

The Key Insight: Query is Just a String Builder

The single most important thing to understand about this class is that it does not perform any queries itself. Its only job is to create specially formatted strings.

Look at the signature of every static method:

  • fun equal(...) = Query(...).toJson()
  • fun limit(...) = Query(...).toJson()
  • fun select(...) = Query(...).toJson()

Each method does two things:

  1. It creates a new, temporary Query object (e.g., Query(method="select", attribute=null, values=listOf("title", "year"))).
  2. It immediately calls .toJson() on that object, which converts it into a string like select(["title", "year"]).

This string is the only thing that gets returned. The listDocuments and getDocument functions simply take a List<String> of these formatted query strings and pass them directly to the Appwrite server in the API request.


How This Explains Both Errors Perfectly

Now we can see the full picture and understand why the two different errors happened.

1. The Attribute not found in schema: $collectionId Error

  • Your Code: Your extension called databases.listDocuments with a list containing the string returned by Query.select(listOf("$id", "$collectionId", "title")).
  • What the SDK Did: It took that string (select(["$id", "$collectionId", "title"])) and sent it to the Appwrite server.
  • What the Server Did: The server received the request. Its code for handling the select parameter is designed to only look at your collection's defined attributes (your schema). It saw "$collectionId", checked your schema, didn't find it, and correctly returned an error.
  • Conclusion: The Query.select method is just a dumb pipe. It passes whatever you give it to the server. The server correctly rejects requests for system attributes via select.

2. The NullPointerException (The Original Crash)

  • Your Code: Your extension called databases.listDocuments with the string from Query.select(listOf("title")).
  • What the SDK Did: It sent the string select(["title"]) to the server.
  • What the Server Did: The server received this valid request. It found the matching documents and, to be efficient, returned only the title for each one. The response looked like {"documents": [{"title": "Avatar"}, {"title": "Lord of the Rings"}]}.
  • What the SDK Did Next: The SDK received this minimal response. It then tried to create Document objects from it using the Document.from() parser we analyzed earlier. That parser requires the $id, $collectionId, etc., fields to be present. Since they were missing from the server's response, it tried to cast null to a String and crashed.

Final, Definitive Recommendation for Your Extension

The source code for Query, Document, and DocumentList confirms the "Catch-22" situation:

  1. To use Query.select, you cannot include system attributes ($id, etc.).
  2. To use the SDK's automatic parsing into Document objects, you must have the system attributes.

These two conditions are mutually exclusive. You cannot satisfy both at the same time.

Therefore, the only robust and correct solution for your MIT App Inventor extension is the one outlined in my previous response:

  1. Do Not Expose Query.select: Remove the selectAttributes parameter from your ListDocuments and GetDocument blocks. They should always fetch the full document data. This avoids both types of errors.
  2. Provide a Client-Side Helper Block: Add the new block SelectAttributesFromDocument(document, keysToSelect). This block will run on the user's device.
  3. Instruct Your Users: Teach them to first call GetDocument or ListDocuments, and then use the new helper block on the result to filter down to the data they need.

This approach is safe, reliable, and gives your users the functionality they want without any risk of crashing the app.

bigraymasoom avatar Jun 26 '25 14:06 bigraymasoom

Is this bug still open or fixed?

bigraymasoom avatar Sep 27 '25 20:09 bigraymasoom

@bigraymasoom its in cycle to be fixed. sharing a small reproducible example will really help us solve this quicker, can you please share one?

ChiragAgg5k avatar Sep 28 '25 01:09 ChiragAgg5k

@ChiragAgg5k Sorry with the late reply buddy. Here is the brief discussion about this error.

https://discord.com/channels/564160730845151244/1255448380033863690

bigraymasoom avatar Nov 18 '25 13:11 bigraymasoom