Java Client: Sometimes a task creation request returns null instead of throwing the actually occurring error

Hey guys,

over the last weeks we have been tracking down a weird Nullpointer that we could finally nail down to the AsanaClient returning null on some task creation requests.

The specific thing about the request where we could analyse the root cause is that it usually fails with a com.asana.errors.InvalidRequestError: Invalid Request (followers: [1]: Not an email, GID, or "me": ) error - but if this request is done often enough at some point it will just return null instead of throwing an exception.

So I’d like to report this inconsistent and flaky behaviour → after the first analysis it would also be great to get an idea if this might affect other object creation methods aswell.

We could observe this behaviour continuously in a flaky manner using the following taskRequestBuilder:

requestBuilder: {
name="my fancy name",
notes="my fancy notes",
assignee="validAssingeeEmail@domain.com",
completed=false,
followers=["validAssigneeEmail.@domain.com",  ""],
projects=["projectId1", "projectId2", "projectId3", "projectId4"]
}

The second follower in the list is an empty string - and usually it would trigger the above mentioned error - but sometimes the API-client just doesn’t report an error but returns a null Task instead (no task is created in asana).

Best Regards,
Ron


Update:
Could now reproduce the same sporadic NullPointer behaviour with the following error smarter.ecommerce.commons.asana.AsanaApiException: com.asana.errors.InvalidRequestError: Invalid Request (projects: [2]: Unknown object: myProjectId)

The behaviour is stable enough that with a repeatedly sending wrong request I can reproduce it in a test!

Hey @Phil_Seeman would you by any chance know to whome to best reach out to for this topic? My go to person which was @Ross_Grambo is not working at asana anymore :sweat_smile:

@Ronald_Findling , I would recommend sending it in an email to api-support at asana dot com.

Thx @Phil_Seeman, my request was forwarded to the engineering team - I’ll keep this thread updated if I get any relevant information.

@Ronald_Findling thanks for reporting this. Are you using a fork of the Java SDK by any chance? I’m trying to understand exactly what code leads to this NPE. Any specific context you can provide based on your investigation would be useful for us to reproduce this.

Hey @Kem_Ozbek to be specific - for reproducing the behaviour in test I used the groovy spock framework:

"org.codehaus.groovy:groovy-all:2.5.11"
"org.spockframework:spock-core:1.3-groovy-2.5"

My local environment where I reproduced it used adopt@1.8.0-232 - but we also saw occurrences on another machine using openjdk-8.

FYI: doing a few hundred wrong requests in a test I could reproduce the NPE every-time I tried :slight_smile:

Hi @Ronald_Findling,

Apologies for the belated reply. Could you please provide a more
specific code sample as well as the stack trace of the error? A gist would be fine.

I’m somewhat unfamiliar with the Java client library. I noticed that you’re
using a taskRequestBuilder in the code sample in the original post. I’m not
seeing that anywhere in our client library. Is that autogenerated by Java, or is
that something you wrote yourself?

Thanks,
Sasha

@sasha_f sry for the long delay (I was on holidays :D).

Yeah the taskRequestBuilder is part of a selfWritten library - I modified my example to use the plain java asana-api-client which can reproduce the described null behaviour (as described before it can take up to a few hundred runs)

    @Unroll
    def "taskCreation sometimes returns to null if it would fail with an error otherwise - v2 - #times"() {
        setup:
        def connectTimeout = 90000
        def readTimeout = 90000
        def client = new Client(new AccessTokenDispatcher(PERSONAL_ACCESS_TOKEN) {
            @Override
            public HttpRequest buildRequest(String method, GenericUrl url, HttpContent content) throws IOException {
                HttpRequest request = httpTransport.createRequestFactory({req ->
                    req.setConnectTimeout(connectTimeout)
                    req.setReadTimeout(readTimeout)
                }).buildRequest(method, url, content)
                request.getHeaders().setAuthorization("Bearer " + PERSONAL_ACCESS_TOKEN)
                return request
            }
        })
        client.headers.put("Asana-Enable", "string_ids,new_user_task_lists,new_project_templates,new_user_task_lists")
        def createdTask = null
        def failed = false
        def request = client.tasks.createInWorkspace(WORKSPACE_ID).data([
                "projects" : [devProject.gid],
                "name" : "My brand new task",
                "html_notes" : "<body>The notes</body>",
                "completed" : false,
                "followers": [DEV_USER_ID, ""]
        ])
        when:
        try {
            println("Execution #${times}")
            createdTask = request.execute()
        } catch(Exception ex) {
            failed = true
            println("Execution #${times} failed with error: ${ex}")
        }
        then:
        if(!failed) println("The execution didn't fail!")
        if(!failed && createdTask == null) println("The execution didn't fail and the returned task is null!")
        where:
        times << (1..10000)
    }

Thanks in advance,
Ron

Hey @sasha_f,
did the new groovy example help or do you need something more?

Best Regards,
Ron

@Kem_Ozbek is it clearer now with the groovy Example or would you need something else?

Kem is on leave till next month…

@sasha_f @AndrewWong