Summary
The DocumentAlreadyExistsException branch of createCustomCheck always reports the collision as a non-archived check, even though it can be reached when the existing check is archived. The user is then told they already have a check that does not appear anywhere in their list.
Details
createCustomCheck first looks the check up and passes the real flag (EligibilityCheckResource.java:91):
return duplicateCheckResponse(request, existingCheck.get().getIsArchived());
but the write-collision branch hardcodes it (EligibilityCheckResource.java:100):
} catch (DocumentAlreadyExistsException e) {
Log.info("Check " + checkId + " was created concurrently");
return duplicateCheckResponse(request, false);
}
For a genuine two-writer race false is right — a just-created check is not archived. The problem is that the branch is also reachable without a race, because the pre-check silently swallows read failures. getWorkingCustomCheck → getCustomCheck (EligibilityCheckRepositoryImpl.java:141) calls FirestoreUtils.getFirestoreDocById, which catches every exception and returns Optional.empty() (FirestoreUtils.java:158):
}catch(Exception e){
Log.error("Error fetching document from firestore: ", e);
return Optional.empty();
}
So any transient read error — deadline exceeded, a blip, an auth hiccup — is indistinguishable from "no such check". The create then fails ALREADY_EXISTS against an existing archived document and the user gets:
You already have a check named "X" in module "Y".
while that check is filtered out of their list (EligibilityCheckRepositoryImpl.java:34) and so cannot be found.
Possible directions
- re-read the document inside the catch and use its actual
isArchived value
- or have the pre-check distinguish "not found" from "read failed", the way
getFirestoreDocsByFields already does, and return a 503 instead of guessing
- or make the collision message status-neutral so it never asserts a state that was not checked
Related to #484 and to the restore gap it exposes.
Summary
The
DocumentAlreadyExistsExceptionbranch ofcreateCustomCheckalways reports the collision as a non-archived check, even though it can be reached when the existing check is archived. The user is then told they already have a check that does not appear anywhere in their list.Details
createCustomCheckfirst looks the check up and passes the real flag (EligibilityCheckResource.java:91):but the write-collision branch hardcodes it (
EligibilityCheckResource.java:100):For a genuine two-writer race
falseis right — a just-created check is not archived. The problem is that the branch is also reachable without a race, because the pre-check silently swallows read failures.getWorkingCustomCheck→getCustomCheck(EligibilityCheckRepositoryImpl.java:141) callsFirestoreUtils.getFirestoreDocById, which catches every exception and returnsOptional.empty()(FirestoreUtils.java:158):So any transient read error — deadline exceeded, a blip, an auth hiccup — is indistinguishable from "no such check". The create then fails
ALREADY_EXISTSagainst an existing archived document and the user gets:while that check is filtered out of their list (
EligibilityCheckRepositoryImpl.java:34) and so cannot be found.Possible directions
isArchivedvaluegetFirestoreDocsByFieldsalready does, and return a 503 instead of guessingRelated to #484 and to the restore gap it exposes.