@@ -53,6 +53,9 @@ class AffiliationService(BaseService):
5353 FILE_PICKER_PREVIEW_MAX_CHARS = 400
5454 FILE_PICKER_BATCH_SIZE = 20
5555
56+ # Conservative safety limit to stay well below asyncpg's bind parameter cap
57+ IDENTITY_LOOKUP_BATCH_SIZE = 500
58+
5659 TEXT_FILE_EXTENSIONS = (
5760 "" ,
5861 ".md" ,
@@ -366,7 +369,10 @@ def _parse_optional_date(value: str | None) -> date | None:
366369 stripped = AffiliationService ._strip (value )
367370 if not stripped :
368371 return None
369- return date .fromisoformat (stripped )
372+ try :
373+ return date .fromisoformat (stripped )
374+ except ValueError :
375+ return None
370376
371377 @classmethod
372378 def group_parse_rows (
@@ -718,10 +724,23 @@ async def apply_affiliations(
718724 )
719725 stint_refs .append ((member_idx , org_idx , organization ))
720726
721- resolved_members = await find_many_member_ids_by_identities (member_identity_inputs )
722- resolved_organizations = await find_many_organization_ids_by_identities (
723- organization_identity_inputs
724- )
727+ resolved_members : list [dict ] = []
728+ for batch_start in range (0 , len (member_identity_inputs ), self .IDENTITY_LOOKUP_BATCH_SIZE ):
729+ batch = member_identity_inputs [
730+ batch_start : batch_start + self .IDENTITY_LOOKUP_BATCH_SIZE
731+ ]
732+ resolved_members .extend (await find_many_member_ids_by_identities (batch ))
733+
734+ resolved_organizations : list [dict ] = []
735+ for batch_start in range (
736+ 0 , len (organization_identity_inputs ), self .IDENTITY_LOOKUP_BATCH_SIZE
737+ ):
738+ batch = organization_identity_inputs [
739+ batch_start : batch_start + self .IDENTITY_LOOKUP_BATCH_SIZE
740+ ]
741+ resolved_organizations .extend (
742+ await find_many_organization_ids_by_identities (batch )
743+ )
725744
726745 resolved_stints : list [tuple [str , str , AffiliationOrganizationStint ]] = []
727746 seen_stints : set [tuple [str , str , date | None , date | None ]] = set ()
0 commit comments