ConcurrentModificationError Mystery

So, today I got bit by the ConcurrentModificationError. I had some code which had a bit of a bad smell but was working fine. The class is a batch process, that processes a request. Based on the request, a particular subset of accounts are processed. The method below gets the target accounts based on the request, and additionally filters out corporate accounts. And the ConcurrentModificationError happens on line 9:

	/**
	 * Get accounts to process based on BatchRequest, filtering out corporate accounts.
	 * @param request
	 */
	public void getAccounts (BatchRequest request) {

		List<Account> accounts = AccountManager.getAccounts(request);

		for (Account oneAccount : accounts) {
			if (isCorporateAccount(oneAccounts)) {
				accounts.remove(oneAccount);
			}
		}

	}

The List which the AccountManager is passing back has a fail-fast iterator, which detects that it is being modified in line 11, and thus failing. The mystery is–this has been working in production for months. Today, on UAT we tested a second batch job with very similar data (for all intents and purposes it is completely the same request, just a different group of accounts) and on the second pass only, the ConcurrentModificationError gets thrown. The first pass through it is fine.

Color me confused. It should work both times, or fail both times. And yes, the data is basically the same–I triple checked that today. But it works the first time, and fails the second.

Rather than spend more time wondering why it works once and fails the second time, I figure I should just eliminate the possibility of the ConcurrentModificationException entirely.  I had to make changes to the AccountManager module, which I hadn’t had the chance to change before. But it is definitely a cleaner solution. By adding a signature to the AccountManager.getAccounts(BatchRequest request, boolean includeCorporateAccounts) I was able to simplify the code to something like this:


	private static final boolean EXCLUDE_CORPORATE_ACCTS_FLAG = false;

	/**
	 * Get accounts to process based on BatchRequest, filtering out corporate accounts.
	 * @param request
	 */
	public void getAccounts (BatchRequest request) {

		return AccountManager.getAccounts(request, EXCLUDE_CORPORATE_ACCTS_FLAG);

	}