So here is some simple code that does work:

Database.QueryLocator ql = Database.getQueryLocator('SELECT Id FROM Account LIMIT 2');
Iterator<SObject> iter = ql.iterator();

Ok. But suppose I have a method that wants to generically be able to take in any kind of sObject Iterable, whether it's a list or QueryLocator or something else custom. So then I'll want to work generically with an Iterator<SObject>.

But this code crashes:

Database.QueryLocator ql = Database.getQueryLocator('SELECT Id FROM Account LIMIT 2');
Iterable<SObject> qlIterable = ql;
Iterator<SObject> iter = qlIterable.iterator();

The casting line works. The iterator() line is the last to execute before I get:


Line: undefined, Column: undefined

Response to EXEC was :

An internal server error has occurred

An error has occurred while processing your request. The salesforce.com support team has been notified of the problem. If you believe you have additional information that may be of help in reproducing or correcting the error, please contact Salesforce Support. Please indicate the URL of the page you were requesting, any error id shown on this page as well as any other related information. We apologize for the inconvenience.

Thank you again for your patience and assistance. And thanks for using salesforce.com!

Error ID: 594482587-81700 (-1994218094) . HTTP CODE[500]

Any thoughts as to why this might be the case? I ended up working around by having a special overload to handle QueryLocator. Still it's weird.

EDIT: Why am I assigning it to an Iterable in the first place? The assignment in the snippet above is equivalent to what happens if I create a method that generically accepts an Iterable<SObject> as an input parameter. I created a parsing method that can take in SObjects either as a QueryLocator or an actual List. If I pass in a QueryLocator, it crashes on the line where I obtain the iterator to loop through it. The snippet above is a minimal example of what it takes to make this crash happen.

  • 1
    Interesting bug. Please note the format here is Q&A, so your post would be well served if you edit its content to include a question proper.
    – Adrian Larson
    Oct 10, 2019 at 19:26
  • @AdrianLarson Thanks, I think I meant to end on a question and forgot to.
    – Charles T
    Oct 10, 2019 at 19:28
  • I just stumbled over the same issue and made an interesting finding. SF internally is able to handle this kind of casting. In my Apex Batch implementation, I am implementing Database.Batchable<SObject> and returning a QueryLocator automatically typed to Iterable<SObject> through the method annotation and the batches are running just fine. I wonder if they are able to call .iterator() internally without issues or if they access the object in any way we don't see (iterator() is the only accessor)
    – itsmebasti
    Apr 30, 2021 at 8:39

3 Answers 3


I stumbled over the same thing and decided to encapsulate this gack into a small class for the future and quickly wanted to contribute it back.

You simply use it like this:

public void myMethod(Iterable<SObject> iterable) {
    iterable = new GackAwareIterable(iterable);


public class GackAwareIterable implements Iterable<Object> {
    private final Iterable<Object> iterable;
    public GackAwareIterable(Iterable<Object> iterable) {
        this.iterable = iterable;
    public Iterator<Object> iterator() {
        Iterator<Object> result;
        if(iterable instanceof Database.QueryLocator) {
            result = (Iterator<Object>) ((Database.QueryLocator) iterable).iterator();
        else {
            result = iterable.iterator();
        return result;

What a bummer there are no generics in Apex. If you prefer simply change the types to SObject to get rid of additional casting. For a simple test, check this Gist


I believe the issue is with the assignment.

In the initial code, you are assigning ql.iterator() returns a QueryLocatorIterator. So, Iterable = ql.iterator() makes sense.

But in your second code, you are trying to assign QueryLocator to Iterable which does not look like the right assignment.

  • But QueryLocator implements Iterable<SObject>. So shouldn't its implementation of the .iterator() method return an object that implements Iterator<SObject>?
    – Charles T
    Oct 10, 2019 at 20:41

More of a long-form observation than an answer, but when I run this in Illuminated Cloud, I get more of an error (sadly, I can't select the text to copy, so screenshot below):

Error via IC

There's some funky stuff going on in Apex to allow

for(SObject o : [SELECT ...])

...to work, and I guess that funkiness is tripping up your useage. I'm pretty sure that the compiler must be handling this as a special case because I've tried to use a querylocator as a normal iterator myself and it doesn't use the querymore method, it just does the whole query in one chunk.

I ended up working around it by making my library code accept either an iterator or an iterable. Then, the user of the library can do the right thing.

As you say, one the face of it, your use looks correct.

  • All interesting to know, thanks. There is some weirdness on how QueryLocator is handled for sure... if I get a QueryLocator on a query that returns way too many records I hit SOQL limits. But if not, then it doesn't count against my max SOQL rows queried until I actually call .next() on the Iterator.
    – Charles T
    Oct 11, 2019 at 12:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .