I noticed this one in the logs today, and it stood out. It looks like we're sending over values to Gravy in recurring charges that they expect to be UUIDs, but instead map to ct_ids and other PSP IDs.
This started happening last month, based on the data.
Validation error during recurring charge, in field: processor_contact_id. Message: Input should be a valid UUID, invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `.` at 10.
Response: {"type":"error","code":"bad_request","status":400,"message":"Request failed validation","details":[{"location":"body","pointer":"/buyer_id","message":"Input should be a valid UUID, invalid character: expected an optional prefix of `urn
:uuid:` followed by [0-9a-fA-F-], found `.` at 10","type":"uuid_parsing"}]}The buyer_id mapping is happening here
if ( !empty( $params['processor_contact_id'] ) ) { $request['buyer_id'] = $params['processor_contact_id']; }
And these values are not UUIDs according to a quick look at the data:
MariaDB [civicrm]> SELECT -> cr.id, -> cr.create_date, -> pp.name AS processor_name, -> crs.processor_contact_id -> FROM -> civicrm_contribution_recur cr -> JOIN civicrm_contribution_recur_smashpig crs ON crs.entity_id = cr.id -> JOIN civicrm_payment_processor pp ON pp.id = cr.payment_processor_id -> WHERE -> cr.payment_processor_id = 19 -> AND crs.processor_contact_id IS NOT NULL -> ORDER BY -> cr.id DESC -> LIMIT -> 20; +---------+---------------------+----------------+----------------------+ | id | create_date | processor_name | processor_contact_id | +---------+---------------------+----------------+----------------------+ | 2778114 | 2026-04-20 00:34:40 | gravy | KYLJRFM3SNKN6 | | 2777222 | 2026-04-17 18:04:04 | gravy | JH9FJCSKGXHNW | | 2775224 | 2026-04-14 18:55:14 | gravy | LHR6KVKQMY7GC | | 2774761 | 2026-04-14 16:29:17 | gravy | TFC95WHAHLHW6 | | 2774760 | 2026-04-14 16:28:54 | gravy | 549927R9MM3PU | | 2773291 | 2026-04-12 10:43:03 | gravy | ZSZ75Z9Y95AB6 | | 2773094 | 2026-04-12 05:58:10 | gravy | EW53MAXV6YZYW | | 2772522 | 2026-04-11 08:24:27 | gravy | SHEK65VA4P49J | | 2772326 | 2026-04-10 22:55:07 | gravy | 834ZVDX2GT54N | | 2772273 | 2026-04-10 21:03:29 | gravy | A34WMZB2L7BNJ | | 2769945 | 2026-04-07 20:00:58 | gravy | 245933565.1 | | 2768592 | 2026-04-06 20:13:22 | gravy | 245953635.1 | | 2768456 | 2026-04-05 20:10:33 | gravy | 245942611.1 | | 2768418 | 2026-04-06 16:10:35 | gravy | XTB72V5JMVG9E | | 2768331 | 2026-04-06 11:29:57 | gravy | RE2THFHU9X4FS | | 2768125 | 2026-04-05 14:34:24 | gravy | 6FPFSGPM3S4MU | | 2767503 | 2026-04-03 07:10:03 | gravy | MFBCDN738D7L6 | | 2766962 | 2026-04-01 16:38:10 | gravy | ARNCA2LT8JZ4J | | 2766645 | 2026-03-31 20:36:55 | gravy | QJS89G6QDE58U | | 2766594 | 2026-03-30 20:25:27 | gravy | 245728521.1 | +---------+---------------------+----------------+----------------------+
Looks like only 33 recurrings are affected here:
MariaDB [civicrm]> SELECT -> COUNT(*) -> FROM -> civicrm_contribution_recur cr -> JOIN civicrm_contribution_recur_smashpig crs ON crs.entity_id = cr.id -> WHERE -> cr.payment_processor_id = 19 -> AND crs.processor_contact_id IS NOT NULL -> AND crs.processor_contact_id NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' -> AND cr.cancel_date IS NULL; +----------+ | COUNT(*) | +----------+ | 33 | +----------+
1049 are UUIDs
MariaDB [civicrm]> SELECT -> COUNT(*) -> FROM -> civicrm_contribution_recur cr -> JOIN civicrm_contribution_recur_smashpig crs ON crs.entity_id = cr.id -> WHERE -> cr.payment_processor_id = 19 -> AND crs.processor_contact_id IS NOT NULL -> AND crs.processor_contact_id REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' -> AND cr.cancel_date IS NULL; +----------+ | COUNT(*) | +----------+ | 1049 | +----------+ 1 row in set (0.330 sec) MariaDB [civicrm]>