How to solve "Can't cast attribute ' cursorID' of type class java.lang.String into class scala.Option?

I am executing cursor pagination loop for millions of data

but I receive errors at attributes

.exec(http("Test:Generate Cursor ID")
  .get("/test")
  .queryParam("sortField", "ID")
  .queryParam("limit", 100)
  .queryParam("cursor", "")
  .check(status.is(200))
  .check(jsonPath("$.nextCursor").saveAs("TestCursorID"))
)

.doWhile(session => session("CursorID").as[Option[String]].isDefined) {
  exec(http("Test:Cursor Pagination")
    .get("/test")
    .queryParam("sortField", "ID")
    .queryParam("limit", 100)
    .queryParam("cursor", "#{TestCursorID}")
    .check(status.is(200))
    .check(jsonPath("$.nextCursor").optional.saveAs("CursorID"))
  )
}

I am receiving below error
Please help me with error

12:49:53.969 [gatling-1-6] DEBUG io.gatling.commons.validation.package$ - j.l.ClassCastException: Can’t cast attribute ‘CursorID’ ‘QUZURVI6aWQ6MDAwMDAwMTAtMDAwMC0wMDEwLTAwMDUtMDAwMDAwMDQ4MzIx’ of type class java.lang.String into class scala.Option
java.lang.ClassCastException: Can’t cast attribute ‘CursorID’ ‘QUZURVI6aWQ6MDAwMDAwMTAtMDAwMC0wMDEwLTAwMDUtMDAwMDAwMDQ4MzIx’ of type class java.lang.String into class scala.Option
at io.gatling.commons.util.LowPriorityTypeCaster$$anon$1.cast(TypeHelper.scala:58)
at io.gatling.commons.util.TypeHelper$.cast(TypeHelper.scala:320)
at io.gatling.core.session.SessionAttribute.as(Session.scala:47)
at CursorBasedPaginationScript.CursorPaginationOnTestScenarioSimulation.$anonfun$scn$3(CursorPaginationOnTestScenarioSimulation.scala:94)
at io.gatling.core.session.package$RichExpression$.$anonfun$safe$extension$1(package.scala:49)
at io.gatling.commons.validation.package$.safely(package.scala:30)
at io.gatling.core.session.package$RichExpression$.$anonfun$safe$1(package.scala:49)
at io.gatling.core.action.builder.LoopBuilder.$anonfun$build$1(LoopBuilder.scala:49)
at io.gatling.core.session.LoopBlock$.continue(Block.scala:38)
at io.gatling.core.action.InnerLoop.execute(Loop.scala:83)
at io.gatling.core.action.Action.$bang(Action.scala:41)
at io.gatling.core.action.Action.$bang$(Action.scala:38)
at …

The error line tells you what the issues and what to fix

Can’t cast attribute ‘CursorID’ ‘QUZURVI6aWQ6MDAwMDAwMTAtMDAwMC0wMDEwLTAwMDUtMDAwMDAwMDQ4MzIx’ of type class java.lang.String into class scala.Option

The optional saveAs does not store an Option it optionally stores if there is something to store.

Solution : fix your doWhile, condition will be if CursorID exists

doWhile(#{CursorID.exists()})
1 Like

Note: the CursorID attribute must be removed at the beginning of the loop. Otherwise, the condition will stay true because of the value fetched in the previous iteration.

1 Like

yes, can you please suggest with an example or syntax.
will be very helpful
or should I adopt for-each?

thanks

Here you go, can you donate to my bit coin here at 00000000000 :stuck_out_tongue: Next time say pretty please

.doWhile(#{CursorID.exists()}) {
  exec(_.remove("CursorID"))
  .exec(http("Test:Cursor Pagination")
    .get("/test")
    .queryParam("sortField", "ID")
    .queryParam("limit", 100)
    .queryParam("cursor", "#{TestCursorID}")
    .check(status.is(200))
    .check(jsonPath("$.nextCursor").saveAs("CursorID"))
  )
}
1 Like

Thank very much :innocent:
pretty please help me understand
but the logic is running in never ending loop

// initialize
exec(session => session.set("CursorID", "")
// loop
.doWhile(#{CursorID.exists()}) {
  exec(http("Test:Cursor Pagination")
    .get("/test")
    .queryParam("sortField", "ID")
    .queryParam("limit", 100)
    .queryParam("cursor", "#{CursorID}")
    .check(status.is(200))
    .check(jsonPath("$.nextCursor").optional.saveAs("NextCursorID"))
  )
  .exec { session =>
    session("NextCursorID").asOption[String] match {
      case Some(nextCursorID) =>
           session
              // update cursor
             .set("CursorID", nextCursorID)
             // remove so we're sure to test the fresh value on next iteration
             .remove("NextCursorID")
      case _ =>
          // end of loop, remove cursor
          session.remove("CursorID")
   }
  }
}
1 Like

Thank you very much :innocent:
@slandelle your solution :sparkles: have solved my issues and thank you very much for the commentary clear explanations :gem:

@shoaib42 thank you for the solutions & support :handshake:

Thanks for your help @shoaib42 !

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.