@@ -1230,25 +1230,23 @@ export class EventRepository {
12301230
12311231 return events ;
12321232 } catch ( error ) {
1233- if ( error instanceof Prisma . PrismaClientUnknownRequestError ) {
1234- logger . error ( "Failed to insert events, most likely because of null characters" , {
1235- error : {
1236- name : error . name ,
1237- message : error . message ,
1238- stack : error . stack ,
1239- clientVersion : error . clientVersion ,
1240- } ,
1233+ if ( isRetriablePrismaError ( error ) ) {
1234+ const isKnownError = error instanceof Prisma . PrismaClientKnownRequestError ;
1235+ span . setAttribute ( "prisma_error_type" , isKnownError ? "known" : "unknown" ) ;
1236+
1237+ const errorDetails = getPrismaErrorDetails ( error ) ;
1238+ if ( errorDetails . code ) {
1239+ span . setAttribute ( "prisma_error_code" , errorDetails . code ) ;
1240+ }
1241+
1242+ logger . error ( "Failed to insert events, will attempt bisection" , {
1243+ error : errorDetails ,
12411244 } ) ;
12421245
12431246 if ( events . length === 1 ) {
12441247 logger . debug ( "Attempting to insert event individually and it failed" , {
12451248 event : events [ 0 ] ,
1246- error : {
1247- name : error . name ,
1248- message : error . message ,
1249- stack : error . stack ,
1250- clientVersion : error . clientVersion ,
1251- } ,
1249+ error : errorDetails ,
12521250 } ) ;
12531251
12541252 span . setAttribute ( "failed_event_count" , 1 ) ;
@@ -1258,12 +1256,7 @@ export class EventRepository {
12581256
12591257 if ( depth > MAX_FLUSH_DEPTH ) {
12601258 logger . error ( "Failed to insert events, reached maximum depth" , {
1261- error : {
1262- name : error . name ,
1263- message : error . message ,
1264- stack : error . stack ,
1265- clientVersion : error . clientVersion ,
1266- } ,
1259+ error : errorDetails ,
12671260 depth,
12681261 eventsCount : events . length ,
12691262 } ) ;
@@ -1917,3 +1910,62 @@ export async function recordRunDebugLog(
19171910 } ,
19181911 } ) ;
19191912}
1913+
1914+ /**
1915+ * Extracts error details from Prisma errors in a type-safe way.
1916+ * Only includes 'code' property for PrismaClientKnownRequestError.
1917+ */
1918+ function getPrismaErrorDetails (
1919+ error : Prisma . PrismaClientUnknownRequestError | Prisma . PrismaClientKnownRequestError
1920+ ) : {
1921+ name : string ;
1922+ message : string ;
1923+ stack : string | undefined ;
1924+ clientVersion : string ;
1925+ code ?: string ;
1926+ } {
1927+ const base = {
1928+ name : error . name ,
1929+ message : error . message ,
1930+ stack : error . stack ,
1931+ clientVersion : error . clientVersion ,
1932+ } ;
1933+
1934+ if ( error instanceof Prisma . PrismaClientKnownRequestError ) {
1935+ return { ...base , code : error . code } ;
1936+ }
1937+
1938+ return base ;
1939+ }
1940+
1941+ /**
1942+ * Checks if a PrismaClientKnownRequestError is a Unicode/hex escape error.
1943+ */
1944+ function isUnicodeError ( error : Prisma . PrismaClientKnownRequestError ) : boolean {
1945+ return (
1946+ error . message . includes ( "lone leading surrogate in hex escape" ) ||
1947+ error . message . includes ( "unexpected end of hex escape" ) ||
1948+ error . message . includes ( "invalid Unicode" ) ||
1949+ error . message . includes ( "invalid escape sequence" )
1950+ ) ;
1951+ }
1952+
1953+ /**
1954+ * Determines if a Prisma error should be retried with bisection logic.
1955+ * Returns true for errors that might be resolved by splitting the batch.
1956+ */
1957+ function isRetriablePrismaError (
1958+ error : unknown
1959+ ) : error is Prisma . PrismaClientUnknownRequestError | Prisma . PrismaClientKnownRequestError {
1960+ if ( error instanceof Prisma . PrismaClientUnknownRequestError ) {
1961+ // Always retry unknown errors with bisection
1962+ return true ;
1963+ }
1964+
1965+ if ( error instanceof Prisma . PrismaClientKnownRequestError ) {
1966+ // Only retry known errors if they're Unicode/hex escape related
1967+ return isUnicodeError ( error ) ;
1968+ }
1969+
1970+ return false ;
1971+ }
0 commit comments