@@ -1458,39 +1458,54 @@ export async function executeSync(
14581458 * Retrying cannot help until the credential is reauthorized, so the
14591459 * connector leaves its schedule with a reconnect prompt instead of
14601460 * climbing the failure ladder toward the same rejection. Reauthorizing
1461- * the credential puts it back on schedule. The run itself is a skip:
1462- * nothing about the source failed, and a sync that cannot start is not
1463- * an incident to page on.
1461+ * the credential puts it back on schedule, and a reauthorization that
1462+ * landed while this run was failing has already cleared the rejection:
1463+ * that run takes the ordinary ladder below, so its next attempt uses the
1464+ * repaired chain rather than leaving a repaired connector unscheduled.
1465+ * The unscheduled run itself is a skip: nothing about the source failed,
1466+ * and a sync that cannot start is not an incident to page on. A run that
1467+ * cannot record the unschedule is a failure, so the runner reports it
1468+ * instead of leaving the connector locked behind a benign outcome.
14641469 */
1465- logger . warn ( 'Sync unscheduled: the source rejected the connector credential' , {
1466- connectorId,
1467- credentialId : error . credentialId ,
1468- errorCode : error . errorCode ,
1469- } )
1470- try {
1471- await completeSyncLog ( syncLogId , 'failed' , result , {
1472- errorMessage : CREDENTIAL_REVOKED_SYNC_ERROR ,
1473- } )
1474- const landed = await writeTerminalConnectorState (
1470+ const stillRejected = await getCredentialTerminalRefreshError ( error . credentialId )
1471+ if ( stillRejected ) {
1472+ logger . warn ( 'Sync unscheduled: the source rejected the connector credential' , {
14751473 connectorId,
1476- syncLogId ,
1477- buildSyncUnscheduledUpdate ( new Date ( ) , CREDENTIAL_REVOKED_SYNC_ERROR )
1478- )
1479- if ( ! landed ) {
1480- logger . warn (
1481- 'Unschedule discarded — connector was reclaimed while this run was executing' ,
1482- { connectorId, syncLogId }
1474+ credentialId : error . credentialId ,
1475+ errorCode : error . errorCode ,
1476+ } )
1477+ try {
1478+ await completeSyncLog ( syncLogId , 'failed' , result , {
1479+ errorMessage : CREDENTIAL_REVOKED_SYNC_ERROR ,
1480+ } )
1481+ const landed = await writeTerminalConnectorState (
1482+ connectorId ,
1483+ syncLogId ,
1484+ buildSyncUnscheduledUpdate ( new Date ( ) , CREDENTIAL_REVOKED_SYNC_ERROR )
14831485 )
1484- }
1485- } catch ( recoveryError ) {
1486- logger . error ( 'Failed to unschedule the connector' , {
1487- connectorId,
1488- error :
1486+ if ( ! landed ) {
1487+ logger . warn (
1488+ 'Unschedule discarded — connector was reclaimed while this run was executing' ,
1489+ { connectorId, syncLogId }
1490+ )
1491+ }
1492+ return { ...result , skipReason : 'credential_revoked' }
1493+ } catch ( recoveryError ) {
1494+ const recoveryMessage =
14891495 getConnectorFailureDiagnostic ( recoveryError ) ?. message ??
1490- toError ( recoveryError ) . message ,
1491- } )
1496+ toError ( recoveryError ) . message
1497+ logger . error ( 'Failed to unschedule the connector' , {
1498+ connectorId,
1499+ error : recoveryMessage ,
1500+ } )
1501+ result . error = recoveryMessage
1502+ return result
1503+ }
14921504 }
1493- return { ...result , skipReason : 'credential_revoked' }
1505+ logger . info ( 'Credential reauthorized during the run; the retry uses the repaired chain' , {
1506+ connectorId,
1507+ credentialId : error . credentialId ,
1508+ } )
14941509 }
14951510
14961511 const diagnostic = getConnectorFailureDiagnostic ( error )
0 commit comments