snowpark-connect 0.30.0__py3-none-any.whl → 0.31.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of snowpark-connect might be problematic. Click here for more details.

Files changed (81) hide show
  1. snowflake/snowpark_connect/column_name_handler.py +150 -25
  2. snowflake/snowpark_connect/config.py +54 -16
  3. snowflake/snowpark_connect/date_time_format_mapping.py +71 -13
  4. snowflake/snowpark_connect/error/error_codes.py +50 -0
  5. snowflake/snowpark_connect/error/error_utils.py +142 -22
  6. snowflake/snowpark_connect/error/exceptions.py +13 -4
  7. snowflake/snowpark_connect/execute_plan/map_execution_command.py +5 -1
  8. snowflake/snowpark_connect/execute_plan/map_execution_root.py +5 -1
  9. snowflake/snowpark_connect/execute_plan/utils.py +5 -1
  10. snowflake/snowpark_connect/expression/function_defaults.py +9 -2
  11. snowflake/snowpark_connect/expression/literal.py +7 -1
  12. snowflake/snowpark_connect/expression/map_cast.py +17 -5
  13. snowflake/snowpark_connect/expression/map_expression.py +48 -4
  14. snowflake/snowpark_connect/expression/map_extension.py +25 -5
  15. snowflake/snowpark_connect/expression/map_sql_expression.py +65 -30
  16. snowflake/snowpark_connect/expression/map_udf.py +10 -2
  17. snowflake/snowpark_connect/expression/map_unresolved_attribute.py +33 -9
  18. snowflake/snowpark_connect/expression/map_unresolved_function.py +627 -205
  19. snowflake/snowpark_connect/expression/map_unresolved_star.py +5 -1
  20. snowflake/snowpark_connect/expression/map_update_fields.py +14 -4
  21. snowflake/snowpark_connect/expression/map_window_function.py +18 -3
  22. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2_grpc.py +4 -0
  23. snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2_grpc.py +4 -0
  24. snowflake/snowpark_connect/relation/catalogs/abstract_spark_catalog.py +65 -17
  25. snowflake/snowpark_connect/relation/catalogs/snowflake_catalog.py +34 -12
  26. snowflake/snowpark_connect/relation/catalogs/utils.py +12 -4
  27. snowflake/snowpark_connect/relation/io_utils.py +66 -4
  28. snowflake/snowpark_connect/relation/map_catalog.py +5 -1
  29. snowflake/snowpark_connect/relation/map_column_ops.py +88 -56
  30. snowflake/snowpark_connect/relation/map_extension.py +28 -8
  31. snowflake/snowpark_connect/relation/map_join.py +21 -10
  32. snowflake/snowpark_connect/relation/map_local_relation.py +5 -1
  33. snowflake/snowpark_connect/relation/map_relation.py +33 -7
  34. snowflake/snowpark_connect/relation/map_row_ops.py +36 -9
  35. snowflake/snowpark_connect/relation/map_sql.py +91 -24
  36. snowflake/snowpark_connect/relation/map_stats.py +25 -6
  37. snowflake/snowpark_connect/relation/map_udtf.py +14 -4
  38. snowflake/snowpark_connect/relation/read/jdbc_read_dbapi.py +49 -13
  39. snowflake/snowpark_connect/relation/read/map_read.py +24 -3
  40. snowflake/snowpark_connect/relation/read/map_read_csv.py +11 -3
  41. snowflake/snowpark_connect/relation/read/map_read_jdbc.py +17 -5
  42. snowflake/snowpark_connect/relation/read/map_read_json.py +8 -2
  43. snowflake/snowpark_connect/relation/read/map_read_parquet.py +13 -3
  44. snowflake/snowpark_connect/relation/read/map_read_socket.py +11 -3
  45. snowflake/snowpark_connect/relation/read/map_read_table.py +15 -5
  46. snowflake/snowpark_connect/relation/read/map_read_text.py +5 -1
  47. snowflake/snowpark_connect/relation/read/metadata_utils.py +5 -1
  48. snowflake/snowpark_connect/relation/stage_locator.py +5 -1
  49. snowflake/snowpark_connect/relation/utils.py +19 -2
  50. snowflake/snowpark_connect/relation/write/jdbc_write_dbapi.py +19 -3
  51. snowflake/snowpark_connect/relation/write/map_write.py +146 -63
  52. snowflake/snowpark_connect/relation/write/map_write_jdbc.py +8 -2
  53. snowflake/snowpark_connect/resources_initializer.py +5 -1
  54. snowflake/snowpark_connect/server.py +72 -19
  55. snowflake/snowpark_connect/type_mapping.py +54 -17
  56. snowflake/snowpark_connect/utils/context.py +42 -1
  57. snowflake/snowpark_connect/utils/describe_query_cache.py +3 -0
  58. snowflake/snowpark_connect/utils/env_utils.py +5 -1
  59. snowflake/snowpark_connect/utils/identifiers.py +11 -3
  60. snowflake/snowpark_connect/utils/pandas_udtf_utils.py +8 -4
  61. snowflake/snowpark_connect/utils/profiling.py +25 -8
  62. snowflake/snowpark_connect/utils/scala_udf_utils.py +11 -3
  63. snowflake/snowpark_connect/utils/session.py +5 -2
  64. snowflake/snowpark_connect/utils/telemetry.py +81 -18
  65. snowflake/snowpark_connect/utils/temporary_view_cache.py +5 -1
  66. snowflake/snowpark_connect/utils/udf_cache.py +5 -3
  67. snowflake/snowpark_connect/utils/udf_helper.py +20 -6
  68. snowflake/snowpark_connect/utils/udf_utils.py +4 -4
  69. snowflake/snowpark_connect/utils/udtf_helper.py +5 -1
  70. snowflake/snowpark_connect/utils/udtf_utils.py +34 -26
  71. snowflake/snowpark_connect/version.py +1 -1
  72. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/METADATA +3 -2
  73. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/RECORD +81 -78
  74. {snowpark_connect-0.30.0.data → snowpark_connect-0.31.0.data}/scripts/snowpark-connect +0 -0
  75. {snowpark_connect-0.30.0.data → snowpark_connect-0.31.0.data}/scripts/snowpark-session +0 -0
  76. {snowpark_connect-0.30.0.data → snowpark_connect-0.31.0.data}/scripts/snowpark-submit +0 -0
  77. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/WHEEL +0 -0
  78. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/licenses/LICENSE-binary +0 -0
  79. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/licenses/LICENSE.txt +0 -0
  80. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/licenses/NOTICE-binary +0 -0
  81. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.31.0.dist-info}/top_level.txt +0 -0
@@ -83,6 +83,8 @@ from snowflake.snowpark_connect.constants import (
83
83
  DUPLICATE_KEY_FOUND_ERROR_TEMPLATE,
84
84
  STRUCTURED_TYPES_ENABLED,
85
85
  )
86
+ from snowflake.snowpark_connect.error.error_codes import ErrorCodes
87
+ from snowflake.snowpark_connect.error.error_utils import attach_custom_error_code
86
88
  from snowflake.snowpark_connect.expression.function_defaults import (
87
89
  inject_function_defaults,
88
90
  )
@@ -188,7 +190,9 @@ def _validate_numeric_args(
188
190
  TypeError: If arguments cannot be converted to numeric types
189
191
  """
190
192
  if len(typed_args) < 2:
191
- raise ValueError(f"{function_name} requires at least 2 arguments")
193
+ exception = ValueError(f"{function_name} requires at least 2 arguments")
194
+ attach_custom_error_code(exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT)
195
+ raise exception
192
196
 
193
197
  modified_args = list(snowpark_args)
194
198
 
@@ -204,9 +208,11 @@ def _validate_numeric_args(
204
208
  # https://github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala#L204
205
209
  modified_args[i] = snowpark_fn.try_cast(snowpark_args[i], DoubleType())
206
210
  case _:
207
- raise TypeError(
211
+ exception = TypeError(
208
212
  f"Data type mismatch: {function_name} requires numeric types, but got {typed_args[0].typ} and {typed_args[1].typ}."
209
213
  )
214
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
215
+ raise exception
210
216
 
211
217
  return modified_args
212
218
 
@@ -407,9 +413,11 @@ def map_unresolved_function(
407
413
  expected_arity = str(valid_arity)
408
414
 
409
415
  if invalid:
410
- raise AnalysisException(
416
+ exception = AnalysisException(
411
417
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `{function_name}` requires {expected_arity} parameters but the actual number is {arity}."
412
418
  )
419
+ attach_custom_error_code(exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT)
420
+ raise exception
413
421
 
414
422
  def _like_util(column, patterns, mode, negate=False):
415
423
  """
@@ -422,9 +430,13 @@ def map_unresolved_function(
422
430
  :return: A Snowpark condition.
423
431
  """
424
432
  if len(patterns) == 0:
425
- raise ParseException("Expected something between '(' and ')'")
433
+ exception = ParseException("Expected something between '(' and ')'")
434
+ attach_custom_error_code(exception, ErrorCodes.INVALID_SQL_SYNTAX)
435
+ raise exception
426
436
  if mode not in ["any", "all"]:
427
- raise ValueError("Mode must be 'any' or 'all'.")
437
+ exception = ValueError("Mode must be 'any' or 'all'.")
438
+ attach_custom_error_code(exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT)
439
+ raise exception
428
440
 
429
441
  if mode == "any":
430
442
  condition = snowpark_fn.lit(False)
@@ -446,9 +458,13 @@ def map_unresolved_function(
446
458
  def _check_percentile_percentage(exp: expressions_proto.Expression) -> Column:
447
459
  perc = unwrap_literal(exp)
448
460
  if perc is None:
449
- raise AnalysisException("The percentage must not be null.")
461
+ exception = AnalysisException("The percentage must not be null.")
462
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
463
+ raise exception
450
464
  if not 0.0 <= perc <= 1.0:
451
- raise AnalysisException("The percentage must be between [0.0, 1.0].")
465
+ exception = AnalysisException("The percentage must be between [0.0, 1.0].")
466
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
467
+ raise exception
452
468
  return snowpark_fn.lit(perc)
453
469
 
454
470
  def _handle_structured_aggregate_result(
@@ -548,9 +564,11 @@ def map_unresolved_function(
548
564
  result_exp = snowpark_fn.lit(None)
549
565
  case (StringType(), StringType()):
550
566
  if spark_sql_ansi_enabled:
551
- raise AnalysisException(
567
+ exception = AnalysisException(
552
568
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("DOUBLE" or "DECIMAL"), not "STRING".'
553
569
  )
570
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
571
+ raise exception
554
572
  else:
555
573
  result_type = DoubleType()
556
574
  result_exp = snowpark_args[0].try_cast(
@@ -612,9 +630,11 @@ def map_unresolved_function(
612
630
  1
613
631
  ].cast(result_type)
614
632
  case _:
615
- raise AnalysisException(
633
+ exception = AnalysisException(
616
634
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").'
617
635
  )
636
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
637
+ raise exception
618
638
  case "+":
619
639
  spark_function_name = _get_spark_function_name(
620
640
  snowpark_typed_args[0],
@@ -660,14 +680,18 @@ def map_unresolved_function(
660
680
  + snowpark_args[t_param_index]
661
681
  )
662
682
  else:
663
- raise AnalysisException(
683
+ exception = AnalysisException(
664
684
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT") type, however "{snowpark_arg_names[t_param_index]}" has the type "{t}".',
665
685
  )
686
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
687
+ raise exception
666
688
  case (StringType(), StringType()):
667
689
  if spark_sql_ansi_enabled:
668
- raise AnalysisException(
690
+ exception = AnalysisException(
669
691
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("NUMERIC" or "INTERVAL DAY TO SECOND" or "INTERVAL YEAR TO MONTH" or "INTERVAL"), not "STRING".'
670
692
  )
693
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
694
+ raise exception
671
695
  else:
672
696
  result_type = DoubleType()
673
697
  result_exp = snowpark_fn.try_cast(
@@ -707,9 +731,11 @@ def map_unresolved_function(
707
731
  case (DecimalType(), t) | (t, DecimalType()) if isinstance(
708
732
  t, (BinaryType, TimestampType)
709
733
  ):
710
- raise AnalysisException(
734
+ exception = AnalysisException(
711
735
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").'
712
736
  )
737
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
738
+ raise exception
713
739
  case _:
714
740
  result_type, overflow_possible = _get_add_sub_result_type(
715
741
  snowpark_typed_args[0].typ,
@@ -782,18 +808,24 @@ def map_unresolved_function(
782
808
  result_type = DateType()
783
809
  result_exp = snowpark_args[0] - snowpark_args[1]
784
810
  case (DateType(), _):
785
- raise AnalysisException(
811
+ exception = AnalysisException(
786
812
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT") type, however "{snowpark_arg_names[1]}" has the type "{snowpark_typed_args[1].typ}".',
787
813
  )
814
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
815
+ raise exception
788
816
  case (_, DateType()):
789
- raise AnalysisException(
817
+ exception = AnalysisException(
790
818
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the "DATE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".',
791
819
  )
820
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
821
+ raise exception
792
822
  case (StringType(), StringType()):
793
823
  if spark_sql_ansi_enabled:
794
- raise AnalysisException(
824
+ exception = AnalysisException(
795
825
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("NUMERIC" or "INTERVAL DAY TO SECOND" or "INTERVAL YEAR TO MONTH" or "INTERVAL"), not "STRING".'
796
826
  )
827
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
828
+ raise exception
797
829
  else:
798
830
  result_type = DoubleType()
799
831
  result_exp = snowpark_fn.try_cast(
@@ -833,9 +865,11 @@ def map_unresolved_function(
833
865
  case (DecimalType(), t) | (t, DecimalType()) if isinstance(
834
866
  t, (BinaryType, TimestampType)
835
867
  ):
836
- raise AnalysisException(
868
+ exception = AnalysisException(
837
869
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").'
838
870
  )
871
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
872
+ raise exception
839
873
  case _:
840
874
  result_type, overflow_possible = _get_add_sub_result_type(
841
875
  snowpark_typed_args[0].typ,
@@ -879,9 +913,11 @@ def map_unresolved_function(
879
913
  result_exp = snowpark_fn.lit(None)
880
914
  case (StringType(), StringType()):
881
915
  if spark_sql_ansi_enabled:
882
- raise AnalysisException(
916
+ exception = AnalysisException(
883
917
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("DOUBLE" or "DECIMAL"), not "STRING".'
884
918
  )
919
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
920
+ raise exception
885
921
  else:
886
922
  result_type = DoubleType()
887
923
  result_exp = _divnull(
@@ -942,9 +978,11 @@ def map_unresolved_function(
942
978
  snowpark_args[1].cast(result_type),
943
979
  )
944
980
  case _:
945
- raise AnalysisException(
981
+ exception = AnalysisException(
946
982
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").'
947
983
  )
984
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
985
+ raise exception
948
986
  case "~":
949
987
  result_exp = TypedColumn(
950
988
  snowpark_fn.bitnot(snowpark_args[0]),
@@ -958,9 +996,11 @@ def map_unresolved_function(
958
996
  or isinstance(snowpark_typed_args[0].typ, BooleanType)
959
997
  and isinstance(snowpark_typed_args[1].typ, DecimalType)
960
998
  ):
961
- raise AnalysisException(
999
+ exception = AnalysisException(
962
1000
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{snowpark_arg_names[0]} < {snowpark_arg_names[1]}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").;'
963
1001
  )
1002
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1003
+ raise exception
964
1004
  # Check for interval-string comparisons
965
1005
  _check_interval_string_comparison(
966
1006
  "<", snowpark_typed_args, snowpark_arg_names
@@ -976,9 +1016,11 @@ def map_unresolved_function(
976
1016
  or isinstance(snowpark_typed_args[0].typ, BooleanType)
977
1017
  and isinstance(snowpark_typed_args[1].typ, DecimalType)
978
1018
  ):
979
- raise AnalysisException(
1019
+ exception = AnalysisException(
980
1020
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{snowpark_arg_names[0]} <= {snowpark_arg_names[1]}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").;'
981
1021
  )
1022
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1023
+ raise exception
982
1024
  # Check for interval-string comparisons
983
1025
  _check_interval_string_comparison(
984
1026
  "<=", snowpark_typed_args, snowpark_arg_names
@@ -1017,9 +1059,11 @@ def map_unresolved_function(
1017
1059
  or isinstance(snowpark_typed_args[0].typ, BooleanType)
1018
1060
  and isinstance(snowpark_typed_args[1].typ, DecimalType)
1019
1061
  ):
1020
- raise AnalysisException(
1062
+ exception = AnalysisException(
1021
1063
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{snowpark_arg_names[0]} > {snowpark_arg_names[1]}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").;'
1022
1064
  )
1065
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1066
+ raise exception
1023
1067
  # Check for interval-string comparisons
1024
1068
  _check_interval_string_comparison(
1025
1069
  ">", snowpark_typed_args, snowpark_arg_names
@@ -1035,9 +1079,11 @@ def map_unresolved_function(
1035
1079
  or isinstance(snowpark_typed_args[0].typ, BooleanType)
1036
1080
  and isinstance(snowpark_typed_args[1].typ, DecimalType)
1037
1081
  ):
1038
- raise AnalysisException(
1082
+ exception = AnalysisException(
1039
1083
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{snowpark_arg_names[0]} >= {snowpark_arg_names[1]}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{snowpark_typed_args[0].typ}" and "{snowpark_typed_args[1].typ}").;'
1040
1084
  )
1085
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1086
+ raise exception
1041
1087
  # Check for interval-string comparisons
1042
1088
  _check_interval_string_comparison(
1043
1089
  ">=", snowpark_typed_args, snowpark_arg_names
@@ -1134,9 +1180,11 @@ def map_unresolved_function(
1134
1180
  )
1135
1181
  case "any":
1136
1182
  if not isinstance(snowpark_typed_args[0].typ, (BooleanType, NullType)):
1137
- raise AnalysisException(
1183
+ exception = AnalysisException(
1138
1184
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the "BOOLEAN" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}".'
1139
1185
  )
1186
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1187
+ raise exception
1140
1188
  result_exp = TypedColumn(
1141
1189
  snowpark_fn.max(snowpark_args[0]),
1142
1190
  lambda: [BooleanType()],
@@ -1151,9 +1199,13 @@ def map_unresolved_function(
1151
1199
  case [col]:
1152
1200
  result_exp = snowpark_fn.any_value(col)
1153
1201
  case _:
1154
- raise ValueError(
1202
+ exception = ValueError(
1155
1203
  f"Unexpected number of args for function any_value. Expected 1 or 2, received {len(snowpark_args)}"
1156
1204
  )
1205
+ attach_custom_error_code(
1206
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
1207
+ )
1208
+ raise exception
1157
1209
 
1158
1210
  spark_function_name = f"any_value({snowpark_arg_names[0]})"
1159
1211
  result_exp = _type_with_typer(result_exp)
@@ -1165,9 +1217,13 @@ def map_unresolved_function(
1165
1217
  lambda: [LongType()],
1166
1218
  )
1167
1219
  case [_, _]:
1168
- raise SnowparkConnectNotImplementedError(
1220
+ exception = SnowparkConnectNotImplementedError(
1169
1221
  "'rsd' parameter is not supported"
1170
1222
  )
1223
+ attach_custom_error_code(
1224
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
1225
+ )
1226
+ raise exception
1171
1227
  case "approx_percentile" | "percentile_approx":
1172
1228
  # SNOW-1955784: Support accuracy parameter
1173
1229
  # Use percentile_disc to return actual values from dataset (matches PySpark behavior)
@@ -1184,7 +1240,11 @@ def map_unresolved_function(
1184
1240
  # Even though the Spark function accepts a Column for percentage, it will fail unless it's a literal.
1185
1241
  # Therefore, we can do error checking right here.
1186
1242
  if not 0.0 <= percentage <= 1.0:
1187
- raise AnalysisException("percentage must be between [0.0, 1.0]")
1243
+ exception = AnalysisException(
1244
+ "percentage must be between [0.0, 1.0]"
1245
+ )
1246
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
1247
+ raise exception
1188
1248
 
1189
1249
  result = snowpark_fn.function("percentile_disc")(
1190
1250
  snowpark_fn.lit(percentage)
@@ -1251,9 +1311,11 @@ def map_unresolved_function(
1251
1311
  case "array_contains":
1252
1312
  array_type = snowpark_typed_args[0].typ
1253
1313
  if not isinstance(array_type, ArrayType):
1254
- raise AnalysisException(
1314
+ exception = AnalysisException(
1255
1315
  f"Expected argument '{snowpark_arg_names[0]}' to have an ArrayType."
1256
1316
  )
1317
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1318
+ raise exception
1257
1319
 
1258
1320
  def _compatible_types(type1: DataType, type2: DataType) -> bool:
1259
1321
  if type1 == type2:
@@ -1273,9 +1335,11 @@ def map_unresolved_function(
1273
1335
  if not _compatible_types(
1274
1336
  array_type.element_type, snowpark_typed_args[1].typ
1275
1337
  ):
1276
- raise AnalysisException(
1338
+ exception = AnalysisException(
1277
1339
  '[DATATYPE_MISMATCH.ARRAY_FUNCTION_DIFF_TYPES] Cannot resolve "array_contains(arr, val)" due to data type mismatch: Input to `array_contains` should have been "ARRAY" followed by a value with same element type'
1278
1340
  )
1341
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1342
+ raise exception
1279
1343
  value = (
1280
1344
  snowpark_fn.cast(snowpark_args[1], array_type.element_type)
1281
1345
  if array_type.structured
@@ -1345,7 +1409,13 @@ def map_unresolved_function(
1345
1409
  )
1346
1410
  result_exp = snowpark_fn.array_to_string(data, delimiter)
1347
1411
  case _:
1348
- raise ValueError(f"Invalid number of arguments to {function_name}")
1412
+ exception = ValueError(
1413
+ f"Invalid number of arguments to {function_name}"
1414
+ )
1415
+ attach_custom_error_code(
1416
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
1417
+ )
1418
+ raise exception
1349
1419
  result_exp = TypedColumn(result_exp, lambda: [StringType()])
1350
1420
  case "array_max":
1351
1421
  result_exp = TypedColumn(
@@ -1437,9 +1507,11 @@ def map_unresolved_function(
1437
1507
  case "array_size":
1438
1508
  array_type = snowpark_typed_args[0].typ
1439
1509
  if not isinstance(array_type, ArrayType):
1440
- raise AnalysisException(
1510
+ exception = AnalysisException(
1441
1511
  f"Expected argument '{snowpark_arg_names[0]}' to have an ArrayType."
1442
1512
  )
1513
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1514
+ raise exception
1443
1515
  result_exp = TypedColumn(
1444
1516
  snowpark_fn.array_size(*snowpark_args), lambda: [LongType()]
1445
1517
  )
@@ -1450,9 +1522,11 @@ def map_unresolved_function(
1450
1522
  snowpark_fn.size(*snowpark_args), lambda: [LongType()]
1451
1523
  )
1452
1524
  else:
1453
- raise AnalysisException(
1525
+ exception = AnalysisException(
1454
1526
  f"Expected argument '{snowpark_arg_names[0]}' to have an ArrayType or MapType, but got {arg_type.simpleString()}."
1455
1527
  )
1528
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1529
+ raise exception
1456
1530
  case "array_sort":
1457
1531
  result_exp = TypedColumn(
1458
1532
  snowpark_fn.array_sort(*snowpark_args),
@@ -1538,9 +1612,13 @@ def map_unresolved_function(
1538
1612
  expr, snowpark_fn.lit(None)
1539
1613
  ).otherwise(raise_error(snowpark_fn.cast(message, StringType())))
1540
1614
  case _:
1541
- raise AnalysisException(
1615
+ exception = AnalysisException(
1542
1616
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `assert_true` requires 1 or 2 parameters but the actual number is {len(snowpark_args)}."
1543
1617
  )
1618
+ attach_custom_error_code(
1619
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
1620
+ )
1621
+ raise exception
1544
1622
  case "atan":
1545
1623
  spark_function_name = f"ATAN({snowpark_arg_names[0]})"
1546
1624
  result_exp = TypedColumn(
@@ -1578,9 +1656,11 @@ def map_unresolved_function(
1578
1656
  # Validate that input is StringType or BinaryType
1579
1657
  input_type = snowpark_typed_args[0].typ
1580
1658
  if not isinstance(input_type, (StringType, BinaryType)):
1581
- raise AnalysisException(
1659
+ exception = AnalysisException(
1582
1660
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "base64({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "BINARY" type, however "{snowpark_arg_names[0]}" has the type "{input_type.simpleString().upper()}".'
1583
1661
  )
1662
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1663
+ raise exception
1584
1664
 
1585
1665
  base64_encoding_function = snowpark_fn.function("base64_encode")
1586
1666
  result_exp = TypedColumn(
@@ -1613,9 +1693,11 @@ def map_unresolved_function(
1613
1693
  if not isinstance(
1614
1694
  snowpark_typed_args[0].typ, (_IntegralType, BooleanType, NullType)
1615
1695
  ):
1616
- raise AnalysisException(
1696
+ exception = AnalysisException(
1617
1697
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the ("INTEGRAL" or "BOOLEAN") type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}"'
1618
1698
  )
1699
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1700
+ raise exception
1619
1701
 
1620
1702
  @cached_udf(
1621
1703
  input_types=[VariantType()],
@@ -1780,9 +1862,11 @@ def map_unresolved_function(
1780
1862
  result_type = BinaryType()
1781
1863
  case "bool_and" | "every":
1782
1864
  if not isinstance(snowpark_typed_args[0].typ, (BooleanType, NullType)):
1783
- raise AnalysisException(
1865
+ exception = AnalysisException(
1784
1866
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the \'BOOLEAN\' type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}".'
1785
1867
  )
1868
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1869
+ raise exception
1786
1870
  bool_and_agg_function = snowpark_fn.function("booland_agg")
1787
1871
  result_exp = TypedColumn(
1788
1872
  bool_and_agg_function(*snowpark_args), lambda: [BooleanType()]
@@ -1790,9 +1874,11 @@ def map_unresolved_function(
1790
1874
 
1791
1875
  case "bool_or" | "some":
1792
1876
  if not isinstance(snowpark_typed_args[0].typ, (BooleanType, NullType)):
1793
- raise AnalysisException(
1877
+ exception = AnalysisException(
1794
1878
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the "BOOLEAN" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}".'
1795
1879
  )
1880
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
1881
+ raise exception
1796
1882
  bool_or_agg_function = snowpark_fn.function("boolor_agg")
1797
1883
  result_exp = TypedColumn(
1798
1884
  bool_or_agg_function(*snowpark_args), lambda: [BooleanType()]
@@ -1825,9 +1911,11 @@ def map_unresolved_function(
1825
1911
  ),
1826
1912
  snowpark_typed_args[0].typ,
1827
1913
  ):
1828
- raise ArithmeticException(
1914
+ exception = ArithmeticException(
1829
1915
  '[ARITHMETIC_OVERFLOW] Overflow. If necessary set "spark.sql.ansi.enabled" to "false" to bypass this error.'
1830
1916
  )
1917
+ attach_custom_error_code(exception, ErrorCodes.ARITHMETIC_ERROR)
1918
+ raise exception
1831
1919
 
1832
1920
  match snowpark_typed_args[0].typ:
1833
1921
  case DecimalType():
@@ -1892,9 +1980,11 @@ def map_unresolved_function(
1892
1980
  if not isinstance(
1893
1981
  snowpark_typed_args[1].typ, IntegerType
1894
1982
  ) and not isinstance(snowpark_typed_args[1].typ, LongType):
1895
- raise AnalysisException(
1983
+ exception = AnalysisException(
1896
1984
  f"The 'scale' parameter of function '{function_name}' needs to be a int literal."
1897
1985
  )
1986
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
1987
+ raise exception
1898
1988
  spark_function_name = (
1899
1989
  f"{fn_name}({snowpark_arg_names[0]}, {snowpark_arg_names[1]})"
1900
1990
  )
@@ -1911,9 +2001,13 @@ def map_unresolved_function(
1911
2001
  else:
1912
2002
  result_exp = TypedColumn(result_exp, lambda: [result_type])
1913
2003
  else:
1914
- raise AnalysisException(
2004
+ exception = AnalysisException(
1915
2005
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `{function_name}` requires 2 parameters but the actual number is {len(snowpark_args)}."
1916
2006
  )
2007
+ attach_custom_error_code(
2008
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
2009
+ )
2010
+ raise exception
1917
2011
  case "chr" | "char":
1918
2012
  result_exp = snowpark_fn.when(
1919
2013
  (snowpark_args[0] > 256), snowpark_fn.char(snowpark_args[0] % 256)
@@ -1949,14 +2043,11 @@ def map_unresolved_function(
1949
2043
  spark_function_name = f"collect_list({snowpark_arg_names[0]})"
1950
2044
  case "collect_set":
1951
2045
  # Convert to a semi-structured type. TODO SNOW-1953065 - Support structured types in array_unique_agg.
1952
- result_exp = snowpark_fn.cast(
1953
- snowpark_fn.array_unique_agg(
1954
- snowpark_typed_args[0].column(to_semi_structure=True)
1955
- ),
1956
- ArrayType(snowpark_typed_args[0].typ),
2046
+ result_exp = snowpark_fn.array_unique_agg(
2047
+ snowpark_typed_args[0].column(to_semi_structure=True)
1957
2048
  )
1958
- result_exp = TypedColumn(
1959
- result_exp, lambda: [ArrayType(snowpark_typed_args[0].typ)]
2049
+ result_exp = _resolve_aggregate_exp(
2050
+ result_exp, ArrayType(snowpark_typed_args[0].typ)
1960
2051
  )
1961
2052
  case "column":
1962
2053
  # TODO: assign type
@@ -2040,9 +2131,11 @@ def map_unresolved_function(
2040
2131
  ),
2041
2132
  ULongLong(),
2042
2133
  ):
2043
- raise ArithmeticException(
2134
+ exception = ArithmeticException(
2044
2135
  '[ARITHMETIC_OVERFLOW] Overflow in function conv(). If necessary set "spark.sql.ansi.enabled" to "false" to bypass this error.'
2045
2136
  )
2137
+ attach_custom_error_code(exception, ErrorCodes.ARITHMETIC_ERROR)
2138
+ raise exception
2046
2139
 
2047
2140
  @cached_udf(
2048
2141
  input_types=[
@@ -2190,9 +2283,11 @@ def map_unresolved_function(
2190
2283
  seed = literal_value
2191
2284
 
2192
2285
  if column is None or eps is None or confidence is None or seed is None:
2193
- raise ValueError(
2286
+ exception = ValueError(
2194
2287
  "The required parameters for count_min_sketch have not been set."
2195
2288
  )
2289
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
2290
+ raise exception
2196
2291
 
2197
2292
  # Calculate depth and width based on eps and confidence
2198
2293
  depth = math.ceil(math.log(1.0 / (1.0 - confidence)))
@@ -2290,10 +2385,12 @@ def map_unresolved_function(
2290
2385
  if not isinstance(col1_type, _NumericType) or not isinstance(
2291
2386
  col2_type, _NumericType
2292
2387
  ):
2293
- raise TypeError(
2388
+ exception = TypeError(
2294
2389
  f"Data type mismatch: covar_pop requires numeric types, "
2295
2390
  f"but got {col1_type} and {col2_type}."
2296
2391
  )
2392
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2393
+ raise exception
2297
2394
  result_exp = snowpark_fn.covar_pop(
2298
2395
  snowpark_args[0],
2299
2396
  snowpark_args[1],
@@ -2305,10 +2402,12 @@ def map_unresolved_function(
2305
2402
  if not isinstance(col1_type, _NumericType) or not isinstance(
2306
2403
  col2_type, _NumericType
2307
2404
  ):
2308
- raise TypeError(
2405
+ exception = TypeError(
2309
2406
  f"Data type mismatch: covar_samp requires numeric types, "
2310
2407
  f"but got {col1_type} and {col2_type}."
2311
2408
  )
2409
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2410
+ raise exception
2312
2411
  result_exp = snowpark_fn.covar_samp(snowpark_args[0], snowpark_args[1])
2313
2412
  result_type = DoubleType()
2314
2413
  case "crc32":
@@ -2317,9 +2416,11 @@ def map_unresolved_function(
2317
2416
  and not isinstance(snowpark_typed_args[0].typ, StringType)
2318
2417
  and not isinstance(snowpark_typed_args[0].typ, VariantType)
2319
2418
  ):
2320
- raise AnalysisException(
2419
+ exception = AnalysisException(
2321
2420
  f"[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve crc32({snowpark_args[0]}) due to data type mismatch: Input requires the BINARY type, however {snowpark_args[0]} has the type {snowpark_typed_args[0].typ}."
2322
2421
  )
2422
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2423
+ raise exception
2323
2424
 
2324
2425
  # UDF to calculate the unsigned CRC32 value of data in bytes. Returns the CRC32 value
2325
2426
  # as a 32-bit INT, or None if the input is None.
@@ -2369,9 +2470,13 @@ def map_unresolved_function(
2369
2470
  spark_function_name = "current_database()"
2370
2471
  case "current_date" | "curdate":
2371
2472
  if len(snowpark_args) > 0:
2372
- raise AnalysisException(
2473
+ exception = AnalysisException(
2373
2474
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `{function_name}` requires 0 parameters but the actual number is {len(snowpark_args)}."
2374
2475
  )
2476
+ attach_custom_error_code(
2477
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
2478
+ )
2479
+ raise exception
2375
2480
  result_exp = TypedColumn(snowpark_fn.current_date(), lambda: [DateType()])
2376
2481
  spark_function_name = "current_date()"
2377
2482
  case "current_timestamp" | "now":
@@ -2387,7 +2492,11 @@ def map_unresolved_function(
2387
2492
  if len(snowpark_args) != 2:
2388
2493
  # SQL supports a 3-argument call that gets mapped to timestamp_add -
2389
2494
  # however, if the first argument is invalid, we end up here.
2390
- raise AnalysisException("date_add takes 2 arguments")
2495
+ exception = AnalysisException("date_add takes 2 arguments")
2496
+ attach_custom_error_code(
2497
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
2498
+ )
2499
+ raise exception
2391
2500
  arg_2 = snowpark_typed_args[1].typ
2392
2501
  if isinstance(arg_2, StringType):
2393
2502
  with suppress(Exception):
@@ -2395,9 +2504,11 @@ def map_unresolved_function(
2395
2504
  arg_2 = IntegerType()
2396
2505
 
2397
2506
  if not isinstance(arg_2, (_IntegralType, NullType)):
2398
- raise AnalysisException(
2507
+ exception = AnalysisException(
2399
2508
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "date_add({snowpark_arg_names[0]}, {snowpark_arg_names[1]})" due to data type mismatch: Parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT" or "NULL") type, however "{snowpark_arg_names[1]}" has the type "{str(arg_2)}".'
2400
2509
  )
2510
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2511
+ raise exception
2401
2512
 
2402
2513
  result_exp = _try_to_cast(
2403
2514
  "try_to_date",
@@ -2412,7 +2523,11 @@ def map_unresolved_function(
2412
2523
  if len(snowpark_args) != 2:
2413
2524
  # SQL supports a 3-argument call that gets mapped to timestamp_diff -
2414
2525
  # however, if the first argument is invalid, we end up here.
2415
- raise AnalysisException("date_diff takes 2 arguments")
2526
+ exception = AnalysisException("date_diff takes 2 arguments")
2527
+ attach_custom_error_code(
2528
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
2529
+ )
2530
+ raise exception
2416
2531
  result_exp = _try_to_cast(
2417
2532
  "try_to_date",
2418
2533
  snowpark_fn.datediff("day", snowpark_args[1], snowpark_args[0]),
@@ -2469,9 +2584,11 @@ def map_unresolved_function(
2469
2584
  arg_2 = IntegerType()
2470
2585
 
2471
2586
  if not isinstance(arg_2, (_IntegralType, NullType)):
2472
- raise AnalysisException(
2587
+ exception = AnalysisException(
2473
2588
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "date_sub({snowpark_arg_names[0]}, {snowpark_arg_names[1]})" due to data type mismatch: Parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT" or "NULL") type, however "{snowpark_arg_names[1]}" has the type "{str(arg_2)}".'
2474
2589
  )
2590
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2591
+ raise exception
2475
2592
  result_exp = _try_to_cast(
2476
2593
  "try_to_date",
2477
2594
  snowpark_fn.to_date(
@@ -2557,9 +2674,11 @@ def map_unresolved_function(
2557
2674
  if isinstance(
2558
2675
  snowpark_typed_args[1].typ, (YearMonthIntervalType, DayTimeIntervalType)
2559
2676
  ):
2560
- raise NotImplementedError(
2677
+ exception = NotImplementedError(
2561
2678
  f"{function_name} with interval types is not supported"
2562
2679
  )
2680
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
2681
+ raise exception
2563
2682
 
2564
2683
  field_lit: str | None = unwrap_literal(exp.unresolved_function.arguments[0])
2565
2684
 
@@ -2637,9 +2756,13 @@ def map_unresolved_function(
2637
2756
  result_exp = snowpark_fn.element_at(data, spark_index)
2638
2757
  result_type = typ.value_type
2639
2758
  case _:
2640
- raise SnowparkConnectNotImplementedError(
2759
+ exception = SnowparkConnectNotImplementedError(
2641
2760
  f"Unsupported type {typ} for element_at function"
2642
2761
  )
2762
+ attach_custom_error_code(
2763
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
2764
+ )
2765
+ raise exception
2643
2766
  case "elt":
2644
2767
  n = snowpark_args[0]
2645
2768
  values = snowpark_fn.array_construct(*snowpark_args[1:])
@@ -2725,9 +2848,11 @@ def map_unresolved_function(
2725
2848
  result_type = [input_type.key_type, input_type.value_type]
2726
2849
  else:
2727
2850
  # Throw proper error for types without key_type/value_type attributes
2728
- raise AnalysisException(
2851
+ exception = AnalysisException(
2729
2852
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{function_name}({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the ("ARRAY" or "MAP") type, however "{snowpark_arg_names[0]}" has the type "{str(input_type)}".'
2730
2853
  )
2854
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
2855
+ raise exception
2731
2856
  case "expm1":
2732
2857
  spark_function_name = f"EXPM1({snowpark_arg_names[0]})"
2733
2858
  result_exp = snowpark_fn.exp(*snowpark_args) - 1
@@ -2848,9 +2973,11 @@ def map_unresolved_function(
2848
2973
  if not isinstance(
2849
2974
  snowpark_typed_args[1].typ, IntegerType
2850
2975
  ) and not isinstance(snowpark_typed_args[1].typ, LongType):
2851
- raise AnalysisException(
2976
+ exception = AnalysisException(
2852
2977
  "The 'scale' parameter of function 'floor' needs to be a int literal."
2853
2978
  )
2979
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
2980
+ raise exception
2854
2981
  spark_function_name = (
2855
2982
  f"floor({snowpark_arg_names[0]}, {snowpark_arg_names[1]})"
2856
2983
  )
@@ -2867,17 +2994,23 @@ def map_unresolved_function(
2867
2994
  else:
2868
2995
  result_exp = TypedColumn(result_exp, lambda: [result_type])
2869
2996
  else:
2870
- raise AnalysisException(
2997
+ exception = AnalysisException(
2871
2998
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `floor` requires 2 parameters but the actual number is {len(snowpark_args)}."
2872
2999
  )
3000
+ attach_custom_error_code(
3001
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
3002
+ )
3003
+ raise exception
2873
3004
  case "format_number":
2874
3005
  col, scale = snowpark_args
2875
3006
  col_type = snowpark_typed_args[0].typ
2876
3007
 
2877
3008
  if not isinstance(col_type, _NumericType):
2878
- raise TypeError(
3009
+ exception = TypeError(
2879
3010
  f'Data type mismatch: Parameter 1 of format_number requires the "NUMERIC" type, however was {col_type}.'
2880
3011
  )
3012
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3013
+ raise exception
2881
3014
 
2882
3015
  @cached_udf(
2883
3016
  input_types=[StringType(), LongType()],
@@ -2953,7 +3086,7 @@ def map_unresolved_function(
2953
3086
  if options is not None:
2954
3087
  if not isinstance(options, dict):
2955
3088
  raise TypeError(
2956
- "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
3089
+ "[snowpark_connect::invalid_input] [INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
2957
3090
  )
2958
3091
 
2959
3092
  max_chars_per_column = options.get(
@@ -2970,7 +3103,7 @@ def map_unresolved_function(
2970
3103
  type(v).__name__, type(v).__name__.upper()
2971
3104
  )
2972
3105
  raise TypeError(
2973
- f'[INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "MAP<{k_type}, {v_type}>".'
3106
+ f'[snowpark_connect::type_mismatch] [INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "MAP<{k_type}, {v_type}>".'
2974
3107
  )
2975
3108
 
2976
3109
  csv_data = csv_data.split(sep)
@@ -2993,7 +3126,7 @@ def map_unresolved_function(
2993
3126
  and len(str(csv_data[i])) > max_chars_per_column
2994
3127
  ):
2995
3128
  raise ValueError(
2996
- f"Max chars per column exceeded {max_chars_per_column}: {str(csv_data[i])}"
3129
+ f"[snowpark_connect::invalid_input] Max chars per column exceeded {max_chars_per_column}: {str(csv_data[i])}"
2997
3130
  )
2998
3131
 
2999
3132
  return results
@@ -3004,9 +3137,11 @@ def map_unresolved_function(
3004
3137
  if len(snowpark_arg_names) > 2 and snowpark_arg_names[2].startswith(
3005
3138
  "named_struct"
3006
3139
  ):
3007
- raise TypeError(
3140
+ exception = TypeError(
3008
3141
  "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
3009
3142
  )
3143
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
3144
+ raise exception
3010
3145
 
3011
3146
  match snowpark_args:
3012
3147
  case [csv_data, schemas]:
@@ -3020,7 +3155,11 @@ def map_unresolved_function(
3020
3155
  snowpark_fn.cast(csv_data, StringType()), schemas, options
3021
3156
  )
3022
3157
  case _:
3023
- raise ValueError("Unrecognized from_csv parameters")
3158
+ exception = ValueError("Unrecognized from_csv parameters")
3159
+ attach_custom_error_code(
3160
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
3161
+ )
3162
+ raise exception
3024
3163
 
3025
3164
  result_exp = snowpark_fn.when(
3026
3165
  snowpark_args[0].is_null(), snowpark_fn.lit(None)
@@ -3029,15 +3168,19 @@ def map_unresolved_function(
3029
3168
  # TODO: support options.
3030
3169
  if len(snowpark_args) > 2:
3031
3170
  if not isinstance(snowpark_typed_args[2].typ, MapType):
3032
- raise AnalysisException(
3171
+ exception = AnalysisException(
3033
3172
  "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
3034
3173
  )
3174
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
3175
+ raise exception
3035
3176
  if not isinstance(
3036
3177
  snowpark_typed_args[2].typ.key_type, StringType
3037
3178
  ) or not isinstance(snowpark_typed_args[2].typ.value_type, StringType):
3038
- raise AnalysisException(
3179
+ exception = AnalysisException(
3039
3180
  f"""[INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "{snowpark_typed_args[2].typ.simpleString().upper()}"."""
3040
3181
  )
3182
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3183
+ raise exception
3041
3184
 
3042
3185
  spark_function_name = f"from_json({snowpark_arg_names[0]})"
3043
3186
  lit_schema = unwrap_literal(exp.unresolved_function.arguments[1])
@@ -3172,9 +3315,11 @@ def map_unresolved_function(
3172
3315
  input_arg_type: DataType,
3173
3316
  format: str = "yyyy-MM-dd HH:mm:ss",
3174
3317
  ):
3175
- raise AnalysisException(
3318
+ exception = AnalysisException(
3176
3319
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "from_unixtime({input_arg_name}, {format})" due to data type mismatch: Parameter 1 requires the "BIGINT" type, however "{input_arg_name}" has the type "{input_arg_type}"'
3177
3320
  )
3321
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3322
+ raise exception
3178
3323
 
3179
3324
  # Strip decimal part of the number to ensure proper result after calling snowflake counterparts
3180
3325
  match snowpark_typed_args[0].typ:
@@ -3240,15 +3385,20 @@ def map_unresolved_function(
3240
3385
  timestamp_format,
3241
3386
  )
3242
3387
  except AnalysisException as e:
3388
+ attach_custom_error_code(e, ErrorCodes.INVALID_INPUT)
3243
3389
  raise e
3244
3390
  except Exception:
3245
3391
  # The second argument must either be a string or none. It can't be a column.
3246
3392
  # So if it's anything that isn't a literal, we catch the error and just return NULL
3247
3393
  result_exp = snowpark_fn.lit(None)
3248
3394
  case _:
3249
- raise AnalysisException(
3395
+ exception = AnalysisException(
3250
3396
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `from_unixtime` requires [1, 2] parameters but the actual number is {len(snowpark_args)}."
3251
3397
  )
3398
+ attach_custom_error_code(
3399
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
3400
+ )
3401
+ raise exception
3252
3402
  result_type = StringType()
3253
3403
  case "from_utc_timestamp":
3254
3404
  target_tz = _map_from_spark_tz(snowpark_args[1])
@@ -3323,10 +3473,12 @@ def map_unresolved_function(
3323
3473
  for sp_col in snowpark_args
3324
3474
  ]
3325
3475
  if current_grouping_cols != spark_col_args:
3326
- raise AnalysisException(
3476
+ exception = AnalysisException(
3327
3477
  f"[GROUPING_ID_COLUMN_MISMATCH] Columns of grouping_id: {spark_col_args} doesnt match "
3328
3478
  f"Grouping columns: {current_grouping_cols}"
3329
3479
  )
3480
+ attach_custom_error_code(exception, ErrorCodes.INTERNAL_ERROR)
3481
+ raise exception
3330
3482
  if function_name == "grouping_id":
3331
3483
  result_exp = snowpark_fn.grouping_id(*snowpark_args)
3332
3484
  else:
@@ -3344,12 +3496,14 @@ def map_unresolved_function(
3344
3496
  if not snowflake_compat and not spark_sql_legacy_allow_hash_on_map_type:
3345
3497
  for arg in snowpark_typed_args:
3346
3498
  if any(isinstance(t, MapType) for t in arg.types):
3347
- raise AnalysisException(
3499
+ exception = AnalysisException(
3348
3500
  '[DATATYPE_MISMATCH.HASH_MAP_TYPE] Cannot resolve "hash(value)" due to data type mismatch: '
3349
3501
  'Input to the function `hash` cannot contain elements of the "MAP" type. '
3350
3502
  'In Spark, same maps may have different hashcode, thus hash expressions are prohibited on "MAP" elements. '
3351
3503
  'To restore previous behavior set "spark.sql.legacy.allowHashOnMapType" to "true".'
3352
3504
  )
3505
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3506
+ raise exception
3353
3507
  result_exp = snowpark_fn.hash(*snowpark_args)
3354
3508
  result_type = LongType()
3355
3509
  case "hex":
@@ -3388,9 +3542,11 @@ def map_unresolved_function(
3388
3542
  if isinstance(aggregate_input_typ, DecimalType):
3389
3543
  # mimic bug from Spark 3.5.3.
3390
3544
  # In 3.5.5 it's fixed and this exception shouldn't be thrown
3391
- raise ValueError(
3545
+ exception = ValueError(
3392
3546
  "class org.apache.spark.sql.types.Decimal cannot be cast to class java.lang.Number (org.apache.spark.sql.types.Decimal is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')"
3393
3547
  )
3548
+ attach_custom_error_code(exception, ErrorCodes.INVALID_CAST)
3549
+ raise exception
3394
3550
 
3395
3551
  histogram_return_type = ArrayType(
3396
3552
  StructType(
@@ -3604,13 +3760,12 @@ def map_unresolved_function(
3604
3760
  input_types=[aggregate_input_typ, IntegerType()],
3605
3761
  )
3606
3762
 
3607
- result_exp = snowpark_fn.cast(
3763
+ result_exp = _resolve_aggregate_exp(
3608
3764
  _histogram_numeric_udaf(
3609
3765
  snowpark_args[0], snowpark_fn.lit(snowpark_args[1])
3610
3766
  ),
3611
3767
  histogram_return_type,
3612
3768
  )
3613
- result_type = histogram_return_type
3614
3769
  case "hll_sketch_agg":
3615
3770
  # check if input type is correct
3616
3771
  if type(snowpark_typed_args[0].typ) not in [
@@ -3620,9 +3775,11 @@ def map_unresolved_function(
3620
3775
  BinaryType,
3621
3776
  ]:
3622
3777
  type_str = snowpark_typed_args[0].typ.simpleString().upper()
3623
- raise AnalysisException(
3778
+ exception = AnalysisException(
3624
3779
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the ("INT" or "BIGINT" or "STRING" or "BINARY") type, however "{snowpark_arg_names[0]}" has the type "{type_str}".'
3625
3780
  )
3781
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3782
+ raise exception
3626
3783
 
3627
3784
  match snowpark_args:
3628
3785
  case [sketch]:
@@ -3761,10 +3918,12 @@ def map_unresolved_function(
3761
3918
  type_mismatched = True
3762
3919
 
3763
3920
  if type_mismatched:
3764
- raise AnalysisException(
3921
+ exception = AnalysisException(
3765
3922
  f'[DATATYPE_MISMATCH.DATA_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: '
3766
3923
  f'Input to `in` should all be the same type, but it\'s [{", ".join(type_names)}].'
3767
3924
  )
3925
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3926
+ raise exception
3768
3927
 
3769
3928
  try:
3770
3929
  result_exp = snowpark_args[0].in_(snowpark_args[1:])
@@ -3797,9 +3956,11 @@ def map_unresolved_function(
3797
3956
  except Exception:
3798
3957
  type_str = str(input_type)
3799
3958
 
3800
- raise AnalysisException(
3959
+ exception = AnalysisException(
3801
3960
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "inline({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "ARRAY<STRUCT>" type, however "{snowpark_arg_names[0]}" has the type {type_str}.'
3802
3961
  )
3962
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
3963
+ raise exception
3803
3964
 
3804
3965
  is_outer = function_name == "inline_outer"
3805
3966
 
@@ -3891,11 +4052,13 @@ def map_unresolved_function(
3891
4052
  if arg_type not in allowed_arg_types:
3892
4053
  spark_type = map_snowpark_to_pyspark_types(arg_type)
3893
4054
 
3894
- raise AnalysisException(
4055
+ exception = AnalysisException(
3895
4056
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: """
3896
4057
  f"""Parameter {arg_idx+3} requires the ("BOOLEAN" or "TINYINT" or "SMALLINT" or "INT" or "BIGINT" or "FLOAT" or "DOUBLE" or "STRING") type, """
3897
4058
  f"""however "{snowpark_arg_names[arg_idx+2]}" has the type "{spark_type.simpleString()}"."""
3898
4059
  )
4060
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4061
+ raise exception
3899
4062
 
3900
4063
  arg_values = snowpark_fn.cast(
3901
4064
  snowpark_fn.array_construct(
@@ -3924,9 +4087,11 @@ def map_unresolved_function(
3924
4087
  if not isinstance(
3925
4088
  snowpark_typed_args[0].typ, StringType
3926
4089
  ) and not isinstance(snowpark_typed_args[0].typ, NullType):
3927
- raise AnalysisException(
4090
+ exception = AnalysisException(
3928
4091
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "json_array_length({",".join(snowpark_arg_names)})" due to data type mismatch: Parameter 1 requires the "STRING" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}"."""
3929
4092
  )
4093
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4094
+ raise exception
3930
4095
  arr_exp = snowpark_fn.function("TRY_PARSE_JSON")(snowpark_args[0])
3931
4096
  result_exp = snowpark_fn.array_size(arr_exp)
3932
4097
  result_type = LongType()
@@ -3934,9 +4099,11 @@ def map_unresolved_function(
3934
4099
  if not isinstance(
3935
4100
  snowpark_typed_args[0].typ, StringType
3936
4101
  ) and not isinstance(snowpark_typed_args[0].typ, NullType):
3937
- raise AnalysisException(
4102
+ exception = AnalysisException(
3938
4103
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "json_object_keys({",".join(snowpark_arg_names)})" due to data type mismatch: Parameter 1 requires the "STRING" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ.simpleString().upper()}"."""
3939
4104
  )
4105
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4106
+ raise exception
3940
4107
  obj_exp = snowpark_fn.function("TRY_PARSE_JSON")(
3941
4108
  snowpark_args[0], snowpark_fn.lit("d")
3942
4109
  )
@@ -4080,9 +4247,11 @@ def map_unresolved_function(
4080
4247
  else snowpark_fn.builtin("try_to_date")(*snowpark_args)
4081
4248
  )
4082
4249
  case _:
4083
- raise AnalysisException(
4250
+ exception = AnalysisException(
4084
4251
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "last_day({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "DATE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0]}".'
4085
4252
  )
4253
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4254
+ raise exception
4086
4255
 
4087
4256
  result_exp = snowpark_fn.last_day(result_exp)
4088
4257
  result_type = DateType()
@@ -4156,7 +4325,13 @@ def map_unresolved_function(
4156
4325
  snowpark_fn.lit(None),
4157
4326
  ).otherwise(snowpark_fn.lit(-1))
4158
4327
  case _:
4159
- raise ValueError(f"Invalid number of arguments to {function_name}")
4328
+ exception = ValueError(
4329
+ f"Invalid number of arguments to {function_name}"
4330
+ )
4331
+ attach_custom_error_code(
4332
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
4333
+ )
4334
+ raise exception
4160
4335
  result_type = LongType()
4161
4336
  case "like":
4162
4337
  result_exp = snowpark_fn.call_function("like", *snowpark_args)
@@ -4400,13 +4575,21 @@ def map_unresolved_function(
4400
4575
  )
4401
4576
  result_type = MapType(NullType(), NullType())
4402
4577
  elif (num_args % 2) == 1:
4403
- raise AnalysisException(
4578
+ exception = AnalysisException(
4404
4579
  f"[WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `map` requires 2n (n > 0) parameters but the actual number is {num_args}"
4405
4580
  )
4581
+ attach_custom_error_code(
4582
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
4583
+ )
4584
+ raise exception
4406
4585
  elif key_type is None or isinstance(key_type, NullType):
4407
- raise SparkRuntimeException(
4586
+ exception = SparkRuntimeException(
4408
4587
  "[NULL_MAP_KEY] Cannot use null as map key."
4409
4588
  )
4589
+ attach_custom_error_code(
4590
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
4591
+ )
4592
+ raise exception
4410
4593
  else:
4411
4594
  value_type = value_type if value_type else NullType()
4412
4595
 
@@ -4452,7 +4635,7 @@ def map_unresolved_function(
4452
4635
  for key, value in m.items():
4453
4636
  if key in new_map and not allow_dups:
4454
4637
  raise ValueError(
4455
- DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)
4638
+ f"[snowpark_connect::invalid_operation] {DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)}"
4456
4639
  )
4457
4640
  else:
4458
4641
  new_map[key] = value
@@ -4483,13 +4666,17 @@ def map_unresolved_function(
4483
4666
  result_type = MapType(key_type, value_type)
4484
4667
  case "map_contains_key":
4485
4668
  if isinstance(snowpark_typed_args[0].typ, NullType):
4486
- raise AnalysisException(
4669
+ exception = AnalysisException(
4487
4670
  f"""[DATATYPE_MISMATCH.MAP_FUNCTION_DIFF_TYPES] Cannot resolve "map_contains_key({snowpark_arg_names[0]}, {snowpark_arg_names[1]})" due to data type mismatch: Input to `map_contains_key` should have been "MAP" followed by a value with same key type, but it's ["VOID", "INT"]."""
4488
4671
  )
4672
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4673
+ raise exception
4489
4674
  if isinstance(snowpark_typed_args[1].typ, NullType):
4490
- raise AnalysisException(
4675
+ exception = AnalysisException(
4491
4676
  f"""[DATATYPE_MISMATCH.NULL_TYPE] Cannot resolve "map_contains_key({snowpark_arg_names[0]}, {snowpark_arg_names[1]})" due to data type mismatch: Null typed values cannot be used as arguments of `map_contains_key`."""
4492
4677
  )
4678
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4679
+ raise exception
4493
4680
  args = (
4494
4681
  [snowpark_args[1], snowpark_args[0]]
4495
4682
  if isinstance(snowpark_typed_args[0].typ, MapType)
@@ -4499,23 +4686,29 @@ def map_unresolved_function(
4499
4686
  result_type = BooleanType()
4500
4687
  case "map_entries":
4501
4688
  if not isinstance(snowpark_typed_args[0].typ, MapType):
4502
- raise AnalysisException(
4689
+ exception = AnalysisException(
4503
4690
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "map_entries({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "MAP" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
4504
4691
  )
4692
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4693
+ raise exception
4505
4694
  key_type = snowpark_typed_args[0].typ.key_type
4506
4695
  value_type = snowpark_typed_args[0].typ.value_type
4507
4696
 
4508
4697
  # SNOW-2040715
4509
4698
  def _map_entries(obj: dict):
4510
4699
  if obj is None:
4511
- raise TypeError(f"Expected MapType but received {obj} instead.")
4700
+ raise TypeError(
4701
+ f"[snowpark_connect::type_mismatch] Expected MapType but received {obj} instead."
4702
+ )
4512
4703
  return [{"key": key, "value": value} for key, value in obj.items()]
4513
4704
 
4514
4705
  arg_type = snowpark_typed_args[0].typ
4515
4706
  if not isinstance(arg_type, MapType):
4516
- raise TypeError(
4707
+ exception = TypeError(
4517
4708
  f"map_entries requires a MapType argument, got {arg_type}"
4518
4709
  )
4710
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4711
+ raise exception
4519
4712
 
4520
4713
  map_entries = snowpark_fn.udf(
4521
4714
  _map_entries,
@@ -4545,9 +4738,11 @@ def map_unresolved_function(
4545
4738
  if not isinstance(keys_type, ArrayType) or not isinstance(
4546
4739
  values_type, ArrayType
4547
4740
  ):
4548
- raise TypeError(
4741
+ exception = TypeError(
4549
4742
  f"map_from_arrays requires two arguments of type ArrayType, got {keys_type} and {values_type}"
4550
4743
  )
4744
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4745
+ raise exception
4551
4746
  key_type = keys_type.element_type if keys_type.structured else VariantType()
4552
4747
  value_type = (
4553
4748
  values_type.element_type if values_type.structured else VariantType()
@@ -4562,7 +4757,7 @@ def map_unresolved_function(
4562
4757
  return None
4563
4758
  if len(keys) != len(values):
4564
4759
  raise ValueError(
4565
- "The key array and value array of must have the same length"
4760
+ "[snowpark_connect::internal_error] The key array and value array of must have the same length"
4566
4761
  )
4567
4762
 
4568
4763
  if not allow_dups and len(set(keys)) != len(keys):
@@ -4570,7 +4765,7 @@ def map_unresolved_function(
4570
4765
  for key in keys:
4571
4766
  if key in seen:
4572
4767
  raise ValueError(
4573
- DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)
4768
+ f"[snowpark_connect::invalid_operation] {DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)}"
4574
4769
  )
4575
4770
  seen.add(key)
4576
4771
  # will overwrite the last occurrence if there are duplicates.
@@ -4592,9 +4787,11 @@ def map_unresolved_function(
4592
4787
  result_type = MapType(key_type, value_type)
4593
4788
  case "map_from_entries":
4594
4789
  if not isinstance(snowpark_typed_args[0].typ, ArrayType):
4595
- raise TypeError(
4790
+ exception = TypeError(
4596
4791
  f"map_from_entries requires an argument of type ArrayType, got {snowpark_typed_args[0].typ}"
4597
4792
  )
4793
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4794
+ raise exception
4598
4795
 
4599
4796
  entry_type = snowpark_typed_args[0].typ.element_type
4600
4797
 
@@ -4613,9 +4810,11 @@ def map_unresolved_function(
4613
4810
  value_type = entry_type.fields[1].datatype
4614
4811
  [key_field, value_field] = entry_type.names
4615
4812
  case _:
4616
- raise TypeError(
4813
+ exception = TypeError(
4617
4814
  f"map_from_entries requires an array of StructType, got array of {entry_type}"
4618
4815
  )
4816
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4817
+ raise exception
4619
4818
 
4620
4819
  last_win_dedup = global_config.spark_sql_mapKeyDedupPolicy == "LAST_WIN"
4621
4820
 
@@ -4656,7 +4855,11 @@ def map_unresolved_function(
4656
4855
  case "map_keys":
4657
4856
  arg_type = snowpark_typed_args[0].typ
4658
4857
  if not isinstance(arg_type, MapType):
4659
- raise TypeError(f"map_keys requires a MapType argument, got {arg_type}")
4858
+ exception = TypeError(
4859
+ f"map_keys requires a MapType argument, got {arg_type}"
4860
+ )
4861
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4862
+ raise exception
4660
4863
 
4661
4864
  if arg_type.structured:
4662
4865
  result_exp = snowpark_fn.map_keys(snowpark_args[0])
@@ -4669,9 +4872,11 @@ def map_unresolved_function(
4669
4872
  # technically this could be done with a lateral join, but it's probably not worth the effort
4670
4873
  arg_type = snowpark_typed_args[0].typ
4671
4874
  if not isinstance(arg_type, (MapType, NullType)):
4672
- raise AnalysisException(
4875
+ exception = AnalysisException(
4673
4876
  f"map_values requires a MapType argument, got {arg_type}"
4674
4877
  )
4878
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4879
+ raise exception
4675
4880
 
4676
4881
  def _map_values(obj: dict) -> list:
4677
4882
  if obj is None:
@@ -4770,20 +4975,30 @@ def map_unresolved_function(
4770
4975
  ):
4771
4976
  pass
4772
4977
  elif not isinstance(arg_type, StringType):
4773
- raise AnalysisException(
4978
+ exception = AnalysisException(
4774
4979
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter {i + 1} requires the "STRING" type, however "{arg_name}" has the type "{arg_type.simpleString().upper()}".;"""
4775
4980
  )
4981
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
4982
+ raise exception
4776
4983
  elif (
4777
4984
  exp.unresolved_function.arguments[i].WhichOneof("expr_type")
4778
4985
  != "literal"
4779
4986
  ):
4780
- raise AnalysisException(
4987
+ exception = AnalysisException(
4781
4988
  f"""[DATATYPE_MISMATCH.NON_FOLDABLE_INPUT] Cannot resolve "{spark_function_name}" due to data type mismatch: the input {col_arg_names[i]} should be a foldable "STRING" expression; however, got "{arg_name}"."""
4782
4989
  )
4990
+ attach_custom_error_code(
4991
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
4992
+ )
4993
+ raise exception
4783
4994
  elif len(arg_name) != 1:
4784
- raise AnalysisException(
4995
+ exception = AnalysisException(
4785
4996
  f"""[DATATYPE_MISMATCH.INPUT_SIZE_NOT_ONE] Cannot resolve "{spark_function_name}" due to data type mismatch: Length of {col_arg_names[i]} should be 1."""
4786
4997
  )
4998
+ attach_custom_error_code(
4999
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
5000
+ )
5001
+ raise exception
4787
5002
 
4788
5003
  random_tag_suffix = "".join(random.sample(string.ascii_uppercase, 6))
4789
5004
  tags = [
@@ -4823,17 +5038,17 @@ def map_unresolved_function(
4823
5038
  # MD5 in Spark only accepts BinaryType or types that can be implicitly cast to it (StringType)
4824
5039
  if not snowflake_compat:
4825
5040
  if not isinstance(snowpark_typed_args[0].typ, (BinaryType, StringType)):
4826
- raise AnalysisException(
5041
+ exception = AnalysisException(
4827
5042
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "md5({snowpark_arg_names[0]})" due to data type mismatch: '
4828
5043
  f'Parameter 1 requires the "BINARY" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".'
4829
5044
  )
5045
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5046
+ raise exception
4830
5047
  result_exp = snowpark_fn.md5(snowpark_args[0])
4831
5048
  result_type = StringType(32)
4832
5049
  case "median":
4833
- result_exp = snowpark_fn.median(snowpark_args[0])
4834
- # TODO SNOW-2034495: can we resolve the result type?
4835
- result_exp = TypedColumn(
4836
- snowpark_fn.cast(result_exp, FloatType()), lambda: [DoubleType()]
5050
+ result_exp = _resolve_aggregate_exp(
5051
+ snowpark_fn.median(snowpark_args[0]), DoubleType()
4837
5052
  )
4838
5053
  case "min":
4839
5054
  result_exp = _handle_structured_aggregate_result(
@@ -4924,9 +5139,13 @@ def map_unresolved_function(
4924
5139
  expanded_args.append(arg_typed_column.col)
4925
5140
 
4926
5141
  if len(expanded_args) % 2 != 0:
4927
- raise ValueError(
5142
+ exception = ValueError(
4928
5143
  "Number of arguments must be even (a list of key-value pairs)."
4929
5144
  )
5145
+ attach_custom_error_code(
5146
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
5147
+ )
5148
+ raise exception
4930
5149
 
4931
5150
  # field types for the schema
4932
5151
  field_names = []
@@ -4998,18 +5217,22 @@ def map_unresolved_function(
4998
5217
  result_exp = snowpark_args[0] * snowpark_fn.lit(-1)
4999
5218
  elif isinstance(arg_type, StringType):
5000
5219
  if spark_sql_ansi_enabled:
5001
- raise NumberFormatException(
5220
+ exception = NumberFormatException(
5002
5221
  f'The value \'{snowpark_args[0]}\' of the type {arg_type} cannot be cast to "DOUBLE" because it is malformed. Correct the value as per the syntax, or change its target type. Use `try_cast` to tolerate malformed input and return NULL instead. If necessary set "spark.sql.ansi.enabled" to "false" to bypass this error.'
5003
5222
  )
5223
+ attach_custom_error_code(exception, ErrorCodes.INVALID_CAST)
5224
+ raise exception
5004
5225
  else:
5005
5226
  result_exp = snowpark_fn.lit(None)
5006
5227
  elif isinstance(arg_type, NullType):
5007
5228
  result_exp = snowpark_fn.lit(None)
5008
5229
  else:
5009
- raise AnalysisException(
5230
+ exception = AnalysisException(
5010
5231
  f"[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve {spark_function_name} due to data type mismatch: "
5011
5232
  f'Parameter 1 requires the ("NUMERIC") type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0]}".'
5012
5233
  )
5234
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5235
+ raise exception
5013
5236
  result_type = (
5014
5237
  snowpark_typed_args[0].types
5015
5238
  if isinstance(arg_type, _NumericType)
@@ -5020,9 +5243,11 @@ def map_unresolved_function(
5020
5243
  date = unwrap_literal(exp.unresolved_function.arguments[1])
5021
5244
  if date is None or date.lower() not in dates:
5022
5245
  if spark_sql_ansi_enabled:
5023
- raise IllegalArgumentException(
5246
+ exception = IllegalArgumentException(
5024
5247
  """Illegal input for day of week. If necessary set "spark.sql.ansi.enabled" to false to bypass this error."""
5025
5248
  )
5249
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
5250
+ raise exception
5026
5251
  else:
5027
5252
  result_exp = snowpark_fn.lit(None)
5028
5253
  else:
@@ -5081,9 +5306,11 @@ def map_unresolved_function(
5081
5306
  )
5082
5307
  case "octet_length":
5083
5308
  if isinstance(snowpark_typed_args[0].typ, (ArrayType, MapType)):
5084
- raise AnalysisException(
5309
+ exception = AnalysisException(
5085
5310
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "octet_length({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the ("STRING" or "BINARY") type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}"."""
5086
5311
  )
5312
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5313
+ raise exception
5087
5314
  result_exp = snowpark_fn.octet_length(snowpark_args[0])
5088
5315
  if isinstance(snowpark_typed_args[0].typ, _FractionalType):
5089
5316
  # All decimal types have to have 3 characters at a minimum.
@@ -5215,9 +5442,11 @@ def map_unresolved_function(
5215
5442
  )
5216
5443
 
5217
5444
  if not isinstance(snowpark_typed_args[0].typ, (_NumericType, StringType)):
5218
- raise AnalysisException(
5445
+ exception = AnalysisException(
5219
5446
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{function_name}({snowpark_arg_names[0]}, {snowpark_arg_names[1]}, {snowpark_arg_names[2]})" due to data type mismatch: Parameter 1 requires the "NUMERIC" type, however "value" has the type "{snowpark_typed_args[0].typ}".;"""
5220
5447
  )
5448
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5449
+ raise exception
5221
5450
  elif len(snowpark_args) == 3:
5222
5451
 
5223
5452
  class PercentileUDAF:
@@ -5237,7 +5466,9 @@ def map_unresolved_function(
5237
5466
  def accumulate(self, value, percentages, frequency: int):
5238
5467
 
5239
5468
  if frequency < 0:
5240
- raise ValueError(f"Negative values found in {frequency}")
5469
+ raise ValueError(
5470
+ f"[snowpark_connect::invalid_input] Negative values found in {frequency}"
5471
+ )
5241
5472
 
5242
5473
  if not self.percentages:
5243
5474
  self.percentages = percentages
@@ -5247,7 +5478,7 @@ def map_unresolved_function(
5247
5478
  for percentage in self.percentages
5248
5479
  ):
5249
5480
  raise ValueError(
5250
- "The percentage must be between [0.0, 1.0]"
5481
+ "[snowpark_connect::invalid_input] The percentage must be between [0.0, 1.0]"
5251
5482
  )
5252
5483
 
5253
5484
  if value is None:
@@ -5293,7 +5524,9 @@ def map_unresolved_function(
5293
5524
  Algorithm based on Spark code: https://github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/aggregate/percentiles.scala#L194
5294
5525
  """
5295
5526
  if not accumulated_counts:
5296
- raise ValueError("accumulated_counts cannot be empty")
5527
+ raise ValueError(
5528
+ "[snowpark_connect::internal_error] accumulated_counts cannot be empty"
5529
+ )
5297
5530
 
5298
5531
  total_count = accumulated_counts[-1][1]
5299
5532
  position = (total_count - 1) * percentile
@@ -5353,7 +5586,7 @@ def map_unresolved_function(
5353
5586
  )
5354
5587
  result_type = DoubleType()
5355
5588
 
5356
- result_exp = snowpark_fn.cast(
5589
+ result_exp = _resolve_aggregate_exp(
5357
5590
  _percentile_udaf(column_value, percentage, snowpark_args[2]),
5358
5591
  result_type,
5359
5592
  )
@@ -5371,19 +5604,14 @@ def map_unresolved_function(
5371
5604
  for arg in array_func.arguments
5372
5605
  ]
5373
5606
  )
5374
- result_exp = snowpark_fn.cast(
5375
- result_exp,
5376
- ArrayType(element_type=FloatType(), contains_null=False),
5377
- )
5378
5607
  result_type = ArrayType(element_type=DoubleType(), contains_null=False)
5608
+ result_exp = _resolve_aggregate_exp(result_exp, result_type)
5379
5609
  spark_function_name = f"{function_name}({snowpark_arg_names[0]}, {snowpark_arg_names[1]}, 1)"
5380
5610
  else:
5381
5611
  result_exp = snowpark_fn.function("percentile_cont")(
5382
5612
  _check_percentile_percentage(exp.unresolved_function.arguments[1])
5383
5613
  ).within_group(column_value)
5384
- result_exp = TypedColumn(
5385
- snowpark_fn.cast(result_exp, FloatType()), lambda: [DoubleType()]
5386
- )
5614
+ result_exp = _resolve_aggregate_exp(result_exp, DoubleType())
5387
5615
  spark_function_name = f"{function_name}({snowpark_arg_names[0]}, {snowpark_arg_names[1]}, 1)"
5388
5616
  case "percentile_cont" | "percentiledisc":
5389
5617
  if function_name == "percentiledisc":
@@ -5428,9 +5656,11 @@ def map_unresolved_function(
5428
5656
  result_exp = snowpark_fn.cast(result_exp, result_type)
5429
5657
  result_exp = TypedColumn(result_exp, lambda: [result_type])
5430
5658
  else:
5431
- raise AnalysisException(
5659
+ exception = AnalysisException(
5432
5660
  f"""pyspark.errors.exceptions.captured.AnalysisException: [DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "{spark_function_name}" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{dividend_type}" and "{divisor_type}")."""
5433
5661
  )
5662
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5663
+ raise exception
5434
5664
  case "posexplode" | "posexplode_outer":
5435
5665
  input_type = snowpark_typed_args[0].typ
5436
5666
  is_nullable = function_name == "posexplode_outer"
@@ -5510,9 +5740,11 @@ def map_unresolved_function(
5510
5740
  input_type.value_type,
5511
5741
  ]
5512
5742
  else:
5513
- raise TypeError(
5743
+ exception = TypeError(
5514
5744
  f"Data type mismatch: {function_name} requires an array or map input, but got {input_type}."
5515
5745
  )
5746
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5747
+ raise exception
5516
5748
  result_exp = snowpark_fn.call_table_function(
5517
5749
  posexplode_udtf.name, snowpark_args[0], snowpark_fn.lit(function_name)
5518
5750
  )
@@ -5539,18 +5771,22 @@ def map_unresolved_function(
5539
5771
  result_exp = snowpark_args[0]
5540
5772
  elif isinstance(arg_type, StringType):
5541
5773
  if spark_sql_ansi_enabled:
5542
- raise NumberFormatException(
5774
+ exception = NumberFormatException(
5543
5775
  f'The value \'{snowpark_args[0]}\' of the type {arg_type} cannot be cast to "DOUBLE" because it is malformed. Correct the value as per the syntax, or change its target type. Use `try_cast` to tolerate malformed input and return NULL instead. If necessary set "spark.sql.ansi.enabled" to "false" to bypass this error.'
5544
5776
  )
5777
+ attach_custom_error_code(exception, ErrorCodes.INVALID_CAST)
5778
+ raise exception
5545
5779
  else:
5546
5780
  result_exp = snowpark_fn.lit(None)
5547
5781
  elif isinstance(arg_type, NullType):
5548
5782
  result_exp = snowpark_fn.lit(None)
5549
5783
  else:
5550
- raise AnalysisException(
5784
+ exception = AnalysisException(
5551
5785
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "(+ {snowpark_arg_names[0]}" due to data type mismatch: '
5552
5786
  f'Parameter 1 requires the ("NUMERIC") type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0]}".'
5553
5787
  )
5788
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5789
+ raise exception
5554
5790
  result_type = (
5555
5791
  snowpark_typed_args[0].types
5556
5792
  if isinstance(arg_type, _NumericType)
@@ -5616,9 +5852,11 @@ def map_unresolved_function(
5616
5852
  if not isinstance(
5617
5853
  snowpark_typed_args[0].typ, (IntegerType, LongType, NullType)
5618
5854
  ):
5619
- raise AnalysisException(
5855
+ exception = AnalysisException(
5620
5856
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 1 requires the ("INT" or "BIGINT") type, however {snowpark_arg_names[0]} has the type "{snowpark_typed_args[0].typ}"""
5621
5857
  )
5858
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
5859
+ raise exception
5622
5860
  result_exp = snowpark_fn.random(unwrap_literal(args[0]))
5623
5861
  else:
5624
5862
  result_exp = snowpark_fn.random()
@@ -6006,9 +6244,11 @@ def map_unresolved_function(
6006
6244
  ),
6007
6245
  snowpark_typed_args[0].typ,
6008
6246
  ):
6009
- raise ArithmeticException(
6247
+ exception = ArithmeticException(
6010
6248
  '[ARITHMETIC_OVERFLOW] Overflow. If necessary set "spark.sql.ansi.enabled" to "false" to bypass this error.'
6011
6249
  )
6250
+ attach_custom_error_code(exception, ErrorCodes.ARITHMETIC_ERROR)
6251
+ raise exception
6012
6252
  if len(snowpark_args) == 1:
6013
6253
  spark_function_name = f"{function_name}({snowpark_arg_names[0]}, 0)"
6014
6254
  result_exp = snowpark_fn.round(snowpark_args[0], snowpark_fn.lit(0))
@@ -6063,21 +6303,25 @@ def map_unresolved_function(
6063
6303
  exp.unresolved_function.arguments[0].WhichOneof("expr_type")
6064
6304
  != "literal"
6065
6305
  ):
6066
- raise AnalysisException(
6306
+ exception = AnalysisException(
6067
6307
  "[DATATYPE_MISMATCH.NON_FOLDABLE_INPUT] Cannot resolve "
6068
6308
  f'"schema_of_csv({snowpark_arg_names[0]})" due to data type mismatch: '
6069
6309
  'the input csv should be a foldable "STRING" expression; however, '
6070
6310
  f'got "{snowpark_arg_names[0]}".'
6071
6311
  )
6312
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
6313
+ raise exception
6072
6314
 
6073
6315
  if isinstance(snowpark_typed_args[0].typ, StringType):
6074
6316
  if exp.unresolved_function.arguments[0].literal.string == "":
6075
- raise AnalysisException(
6317
+ exception = AnalysisException(
6076
6318
  "[DATATYPE_MISMATCH.NON_FOLDABLE_INPUT] Cannot resolve "
6077
6319
  f'"schema_of_csv({snowpark_arg_names[0]})" due to data type mismatch: '
6078
6320
  'the input csv should be a foldable "STRING" expression; however, '
6079
6321
  f'got "{snowpark_arg_names[0]}".'
6080
6322
  )
6323
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
6324
+ raise exception
6081
6325
 
6082
6326
  snowpark_args = [
6083
6327
  typed_arg.column(to_semi_structure=True)
@@ -6132,7 +6376,11 @@ def map_unresolved_function(
6132
6376
  case [csv_data, options]:
6133
6377
  result_exp = _schema_of_csv(csv_data, options)
6134
6378
  case _:
6135
- raise ValueError("Unrecognized from_csv parameters")
6379
+ exception = ValueError("Unrecognized from_csv parameters")
6380
+ attach_custom_error_code(
6381
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
6382
+ )
6383
+ raise exception
6136
6384
  result_type = StringType()
6137
6385
  case "schema_of_json":
6138
6386
 
@@ -6250,15 +6498,19 @@ def map_unresolved_function(
6250
6498
  obj = json.loads(json_str)
6251
6499
  return _infer_pyspark_type(obj)
6252
6500
  except json.JSONDecodeError as e:
6253
- raise ValueError(f"Invalid JSON: {e}")
6501
+ raise ValueError(
6502
+ f"[snowpark_connect::invalid_input] Invalid JSON: {e}"
6503
+ )
6254
6504
 
6255
6505
  if (
6256
6506
  exp.unresolved_function.arguments[0].WhichOneof("expr_type")
6257
6507
  != "literal"
6258
6508
  ):
6259
- raise AnalysisException(
6509
+ exception = AnalysisException(
6260
6510
  f"""[DATATYPE_MISMATCH.NON_FOLDABLE_INPUT] Cannot resolve "schema_of_json({",".join(snowpark_arg_names)})" due to data type mismatch: the input json should be a foldable "STRING" expression; however, got "{",".join(snowpark_arg_names)}"."""
6261
6511
  )
6512
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
6513
+ raise exception
6262
6514
  result_exp = _infer_schema(snowpark_args[0])
6263
6515
  result_type = StringType()
6264
6516
  case "sec":
@@ -6299,12 +6551,14 @@ def map_unresolved_function(
6299
6551
  not isinstance(snowpark_typed_args[0].typ, _IntegralType)
6300
6552
  or not isinstance(snowpark_typed_args[1].typ, _IntegralType)
6301
6553
  ):
6302
- raise AnalysisException(
6554
+ exception = AnalysisException(
6303
6555
  f"""[DATATYPE_MISMATCH.SEQUENCE_WRONG_INPUT_TYPES] Cannot resolve "sequence({snowpark_arg_names[0]}, {snowpark_arg_names[1]})" due to data type mismatch: `sequence` uses the wrong parameter type. The parameter type must conform to:
6304
6556
  1. The start and stop expressions must resolve to the same type.
6305
6557
  2. Otherwise, if start and stop expressions resolve to the "INTEGRAL" type, then the step expression must resolve to the same type.
6306
6558
  """
6307
6559
  )
6560
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
6561
+ raise exception
6308
6562
  result_exp = snowpark_fn.cast(
6309
6563
  snowpark_fn.sequence(*snowpark_args),
6310
6564
  ArrayType(LongType(), contains_null=False),
@@ -6322,15 +6576,21 @@ def map_unresolved_function(
6322
6576
  num_bits = unwrap_literal(exp.unresolved_function.arguments[1])
6323
6577
  if num_bits is None:
6324
6578
  if spark_sql_ansi_enabled:
6325
- raise NumberFormatException(
6579
+ exception = NumberFormatException(
6326
6580
  f"""[CAST_INVALID_INPUT] The value {snowpark_arg_names[0]} of the type "{snowpark_typed_args[0].typ}" cannot be cast to "INT" because it is malformed. Correct the value as per the syntax, or change its target type."""
6327
6581
  )
6582
+ attach_custom_error_code(exception, ErrorCodes.INVALID_CAST)
6583
+ raise exception
6328
6584
  result_exp = snowpark_fn.lit(None)
6329
6585
  result_type = StringType()
6330
6586
  elif num_bits not in bit_values:
6331
- raise IllegalArgumentException(
6587
+ exception = IllegalArgumentException(
6332
6588
  f"""requirement failed: numBits {num_bits} is not in the permitted values (0, 224, 256, 384, 512)"""
6333
6589
  )
6590
+ attach_custom_error_code(
6591
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
6592
+ )
6593
+ raise exception
6334
6594
  else:
6335
6595
  # 0 equivalent to 256 in PySpark, but is not allowed in Snowpark
6336
6596
  num_bits = 256 if num_bits == 0 else num_bits
@@ -6504,9 +6764,11 @@ def map_unresolved_function(
6504
6764
  if len(snowpark_args) == 2 and not isinstance(
6505
6765
  snowpark_typed_args[1].typ, BooleanType
6506
6766
  ):
6507
- raise AnalysisException(
6767
+ exception = AnalysisException(
6508
6768
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: Parameter 2 requires the "BOOLEAN" type, however "{snowpark_arg_names[1]}" has the type "{snowpark_typed_args[1].typ.simpleString().upper()}"'
6509
6769
  )
6770
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
6771
+ raise exception
6510
6772
  sort_asc = (
6511
6773
  unwrap_literal(exp.unresolved_function.arguments[1])
6512
6774
  if len(snowpark_args) == 2
@@ -6557,10 +6819,10 @@ def map_unresolved_function(
6557
6819
  import re
6558
6820
 
6559
6821
  try:
6560
- re.compile(pattern)
6822
+ compiled_pattern = re.compile(pattern)
6561
6823
  except re.error:
6562
6824
  raise ValueError(
6563
- f"Failed to split string, provided pattern: {pattern} is invalid"
6825
+ f"[snowpark_connect::invalid_input] Failed to split string, provided pattern: {pattern} is invalid"
6564
6826
  )
6565
6827
 
6566
6828
  if limit == 1:
@@ -6579,7 +6841,7 @@ def map_unresolved_function(
6579
6841
 
6580
6842
  match pattern:
6581
6843
  case "|":
6582
- split_result = re.split(pattern, input, 0)
6844
+ split_result = compiled_pattern.split(input, 0)
6583
6845
  input_limit = limit + 1 if limit > 0 else len(split_result)
6584
6846
  return (
6585
6847
  split_result
@@ -6591,7 +6853,7 @@ def map_unresolved_function(
6591
6853
  case "^":
6592
6854
  return [input]
6593
6855
  case _:
6594
- return re.split(pattern, input, maxsplit)
6856
+ return compiled_pattern.split(input, maxsplit)
6595
6857
 
6596
6858
  def split_string(str_: Column, pattern: Column, limit: Column):
6597
6859
  native_split = _split(str_, pattern, limit)
@@ -6639,7 +6901,13 @@ def map_unresolved_function(
6639
6901
  case [str_, pattern, limit]: # noqa: F841
6640
6902
  result_exp = split_string(str_, pattern, limit)
6641
6903
  case _:
6642
- raise ValueError(f"Invalid number of arguments to {function_name}")
6904
+ exception = ValueError(
6905
+ f"Invalid number of arguments to {function_name}"
6906
+ )
6907
+ attach_custom_error_code(
6908
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
6909
+ )
6910
+ raise exception
6643
6911
  case "split_part":
6644
6912
  result_exp = snowpark_fn.call_function("split_part", *snowpark_args)
6645
6913
  result_type = StringType()
@@ -6649,9 +6917,11 @@ def map_unresolved_function(
6649
6917
  if isinstance(snowpark_typed_args[0].typ, StringType):
6650
6918
  sqrt_arg = snowpark_fn.try_cast(snowpark_args[0], DoubleType())
6651
6919
  elif not isinstance(snowpark_typed_args[0].typ, _NumericType):
6652
- raise AnalysisException(
6920
+ exception = AnalysisException(
6653
6921
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "SQRT({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}"."""
6654
6922
  )
6923
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
6924
+ raise exception
6655
6925
  result_exp = (
6656
6926
  snowpark_fn.when(sqrt_arg < 0, NAN)
6657
6927
  .when(sqrt_arg.isNull(), snowpark_fn.lit(None))
@@ -6663,16 +6933,22 @@ def map_unresolved_function(
6663
6933
  # will depend on the input specified. All arguments in the input (apart from the first one that specifies
6664
6934
  # `num_rows`) must be the same type.
6665
6935
  if len(exp.unresolved_function.arguments) <= 1:
6666
- raise AnalysisException(
6936
+ exception = AnalysisException(
6667
6937
  f"""
6668
6938
  [WRONG_NUM_ARGS.WITHOUT_SUGGESTION] The `stack` requires > 1 parameters but the actual number is {len(exp.unresolved_function.arguments)}.
6669
6939
  """
6670
6940
  )
6941
+ attach_custom_error_code(
6942
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
6943
+ )
6944
+ raise exception
6671
6945
  num_rows = unwrap_literal(exp.unresolved_function.arguments[0])
6672
6946
  if not isinstance(snowpark_typed_args[0].typ, IntegerType):
6673
- raise AnalysisException(
6947
+ exception = AnalysisException(
6674
6948
  f"""[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "INT" type, however "{num_rows}" has the type "{snowpark_typed_args[0].typ}"."""
6675
6949
  )
6950
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
6951
+ raise exception
6676
6952
 
6677
6953
  num_arguments = len(snowpark_args) - 1
6678
6954
  num_cols = math.ceil(num_arguments / num_rows)
@@ -6683,9 +6959,11 @@ def map_unresolved_function(
6683
6959
  if arg != spark_col_types[i % num_cols] and not isinstance(
6684
6960
  arg, NullType
6685
6961
  ):
6686
- raise AnalysisException(
6962
+ exception = AnalysisException(
6687
6963
  f"""[DATATYPE_MISMATCH.STACK_COLUMN_DIFF_TYPES] Cannot resolve "stack({snowpark_arg_names[0]})" due to data type mismatch: The data type of the column ({snowpark_arg_names[0]}) do not have the same type."""
6688
6964
  )
6965
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
6966
+ raise exception
6689
6967
  if isinstance(arg, NullType):
6690
6968
  spark_col_types[i] = VariantType()
6691
6969
  snowpark_args[i + 1] = snowpark_fn.cast(
@@ -6742,9 +7020,11 @@ def map_unresolved_function(
6742
7020
  snowpark_args[0], DoubleType()
6743
7021
  )
6744
7022
  else:
6745
- raise AnalysisException(
7023
+ exception = AnalysisException(
6746
7024
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "stddev({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
6747
7025
  )
7026
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7027
+ raise exception
6748
7028
  result_exp = snowpark_fn.stddev(stddev_argument)
6749
7029
  result_type = DoubleType()
6750
7030
  case "stddev_pop":
@@ -6755,9 +7035,11 @@ def map_unresolved_function(
6755
7035
  snowpark_args[0], DoubleType()
6756
7036
  )
6757
7037
  else:
6758
- raise AnalysisException(
7038
+ exception = AnalysisException(
6759
7039
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "stddev_pop({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
6760
7040
  )
7041
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7042
+ raise exception
6761
7043
  result_exp = snowpark_fn.stddev_pop(stddev_pop_argument)
6762
7044
  result_type = DoubleType()
6763
7045
  case "stddev_samp" | "std":
@@ -6768,9 +7050,11 @@ def map_unresolved_function(
6768
7050
  snowpark_args[0], DoubleType()
6769
7051
  )
6770
7052
  else:
6771
- raise AnalysisException(
7053
+ exception = AnalysisException(
6772
7054
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "stddev_samp({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
6773
7055
  )
7056
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7057
+ raise exception
6774
7058
  result_exp = snowpark_fn.stddev_samp(stddev_samp_argument)
6775
7059
  result_type = DoubleType()
6776
7060
  case "str_to_map":
@@ -6818,7 +7102,7 @@ def map_unresolved_function(
6818
7102
 
6819
7103
  if key in result_map and not allow_dups:
6820
7104
  raise ValueError(
6821
- DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)
7105
+ f"[snowpark_connect::invalid_input] {DUPLICATE_KEY_FOUND_ERROR_TEMPLATE.format(key=key)}"
6822
7106
  )
6823
7107
 
6824
7108
  result_map[key] = val
@@ -6957,9 +7241,11 @@ def map_unresolved_function(
6957
7241
  result_type = TimestampType(snowpark.types.TimestampTimeZone.LTZ)
6958
7242
  case "timestamp_millis":
6959
7243
  if not isinstance(snowpark_typed_args[0].typ, _IntegralType):
6960
- raise AnalysisException(
7244
+ exception = AnalysisException(
6961
7245
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "timestamp_millis({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the "INTEGRAL" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".'
6962
7246
  )
7247
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7248
+ raise exception
6963
7249
  result_exp = snowpark_fn.cast(
6964
7250
  snowpark_fn.to_timestamp(snowpark_args[0] * 1_000, 6),
6965
7251
  TimestampType(snowpark.types.TimestampTimeZone.LTZ),
@@ -6970,9 +7256,11 @@ def map_unresolved_function(
6970
7256
  # even though the documentation explicitly says that it does.
6971
7257
  # As a workaround, use integer milliseconds instead of fractional seconds.
6972
7258
  if not isinstance(snowpark_typed_args[0].typ, _NumericType):
6973
- raise AnalysisException(
7259
+ exception = AnalysisException(
6974
7260
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{function_name}({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "NUMERIC" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
6975
7261
  )
7262
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7263
+ raise exception
6976
7264
  result_exp = snowpark_fn.cast(
6977
7265
  snowpark_fn.to_timestamp(
6978
7266
  snowpark_fn.cast(snowpark_args[0] * 1_000_000, LongType()), 6
@@ -7145,7 +7433,7 @@ def map_unresolved_function(
7145
7433
  if options is not None:
7146
7434
  if not isinstance(options, dict):
7147
7435
  raise TypeError(
7148
- "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
7436
+ "[snowpark_connect::invalid_input] [INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
7149
7437
  )
7150
7438
 
7151
7439
  python_to_snowflake_type = {
@@ -7164,7 +7452,7 @@ def map_unresolved_function(
7164
7452
  type(v).__name__, type(v).__name__.upper()
7165
7453
  )
7166
7454
  raise TypeError(
7167
- f'[INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "MAP<{k_type}, {v_type}>".'
7455
+ f'[snowpark_connect::type_mismatch] [INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "MAP<{k_type}, {v_type}>".'
7168
7456
  )
7169
7457
 
7170
7458
  options = options or {}
@@ -7302,7 +7590,7 @@ def map_unresolved_function(
7302
7590
  result.append(escape_and_quote_string(str_value))
7303
7591
  case _:
7304
7592
  raise ValueError(
7305
- f"Unable to determine type for value: {python_type}"
7593
+ f"[snowpark_connect::type_mismatch] Unable to determine type for value: {python_type}"
7306
7594
  )
7307
7595
  elif isinstance(value, str):
7308
7596
  strip_value = (
@@ -7335,9 +7623,11 @@ def map_unresolved_function(
7335
7623
  if len(snowpark_arg_names) > 1 and snowpark_arg_names[1].startswith(
7336
7624
  "named_struct"
7337
7625
  ):
7338
- raise TypeError(
7626
+ exception = TypeError(
7339
7627
  "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
7340
7628
  )
7629
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
7630
+ raise exception
7341
7631
 
7342
7632
  def get_snowpark_type_name(snowpark_type: DataType) -> str:
7343
7633
  return (
@@ -7370,7 +7660,11 @@ def map_unresolved_function(
7370
7660
  case [csv_data, options]:
7371
7661
  result_exp = _to_csv(csv_data, field_names, field_types, options)
7372
7662
  case _:
7373
- raise ValueError("Unrecognized from_csv parameters")
7663
+ exception = ValueError("Unrecognized from_csv parameters")
7664
+ attach_custom_error_code(
7665
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
7666
+ )
7667
+ raise exception
7374
7668
  result_type = StringType()
7375
7669
  case "to_date":
7376
7670
  if not spark_sql_ansi_enabled:
@@ -7397,23 +7691,29 @@ def map_unresolved_function(
7397
7691
  case NullType():
7398
7692
  result_exp = snowpark_fn.lit(None)
7399
7693
  case _:
7400
- raise AnalysisException(
7694
+ exception = AnalysisException(
7401
7695
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "to_date({snowpark_arg_names[0]}" due to data type mismatch: Parameter 1 requires the ("STRING" or "DATE" or "TIMESTAMP" or "TIMESTAMP_NTZ") type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".'
7402
7696
  )
7697
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7698
+ raise exception
7403
7699
 
7404
7700
  result_type = DateType()
7405
7701
  case "to_json":
7406
7702
  if len(snowpark_args) > 1:
7407
7703
  if not isinstance(snowpark_typed_args[1].typ, MapType):
7408
- raise AnalysisException(
7704
+ exception = AnalysisException(
7409
7705
  "[INVALID_OPTIONS.NON_MAP_FUNCTION] Invalid options: Must use the `map()` function for options."
7410
7706
  )
7707
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
7708
+ raise exception
7411
7709
  if not isinstance(
7412
7710
  snowpark_typed_args[1].typ.key_type, StringType
7413
7711
  ) or not isinstance(snowpark_typed_args[1].typ.value_type, StringType):
7414
- raise AnalysisException(
7712
+ exception = AnalysisException(
7415
7713
  f"""[INVALID_OPTIONS.NON_STRING_TYPE] Invalid options: A type of keys and values in `map()` must be string, but got "{snowpark_typed_args[1].typ.simpleString().upper()}"."""
7416
7714
  )
7715
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
7716
+ raise exception
7417
7717
  result_exp = snowpark_fn.to_json(snowpark_fn.to_variant(snowpark_args[0]))
7418
7718
  result_type = StringType()
7419
7719
  case "to_number":
@@ -7468,7 +7768,13 @@ def map_unresolved_function(
7468
7768
  )
7469
7769
  )
7470
7770
  case _:
7471
- raise ValueError(f"Invalid number of arguments to {function_name}")
7771
+ exception = ValueError(
7772
+ f"Invalid number of arguments to {function_name}"
7773
+ )
7774
+ attach_custom_error_code(
7775
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
7776
+ )
7777
+ raise exception
7472
7778
  result_exp = snowpark_fn.cast(result_exp, get_timestamp_type())
7473
7779
  result_type = get_timestamp_type()
7474
7780
 
@@ -7486,7 +7792,13 @@ def map_unresolved_function(
7486
7792
  ),
7487
7793
  )
7488
7794
  case _:
7489
- raise ValueError(f"Invalid number of arguments to {function_name}")
7795
+ exception = ValueError(
7796
+ f"Invalid number of arguments to {function_name}"
7797
+ )
7798
+ attach_custom_error_code(
7799
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
7800
+ )
7801
+ raise exception
7490
7802
  result_exp = snowpark_fn.cast(
7491
7803
  result_exp, TimestampType(snowpark.types.TimestampTimeZone.LTZ)
7492
7804
  )
@@ -7511,7 +7823,13 @@ def map_unresolved_function(
7511
7823
  ),
7512
7824
  )
7513
7825
  case _:
7514
- raise ValueError(f"Invalid number of arguments to {function_name}")
7826
+ exception = ValueError(
7827
+ f"Invalid number of arguments to {function_name}"
7828
+ )
7829
+ attach_custom_error_code(
7830
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
7831
+ )
7832
+ raise exception
7515
7833
  result_exp = snowpark_fn.cast(
7516
7834
  result_exp, TimestampType(snowpark.types.TimestampTimeZone.NTZ)
7517
7835
  )
@@ -7553,9 +7871,13 @@ def map_unresolved_function(
7553
7871
  snowpark_fn.lit("YYYY-MM-DD HH24:MI:SS"),
7554
7872
  )
7555
7873
  case _:
7556
- raise SnowparkConnectNotImplementedError(
7874
+ exception = SnowparkConnectNotImplementedError(
7557
7875
  "to_unix_timestamp expected 1 or 2 arguments."
7558
7876
  )
7877
+ attach_custom_error_code(
7878
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
7879
+ )
7880
+ raise exception
7559
7881
 
7560
7882
  if len(exp.unresolved_function.arguments) == 1:
7561
7883
  spark_function_name = f"to_unix_timestamp({snowpark_arg_names[0]}, {'yyyy-MM-dd HH:mm:ss'})"
@@ -7620,9 +7942,13 @@ def map_unresolved_function(
7620
7942
  # Check for interval types and throw NotImplementedError
7621
7943
  for arg in snowpark_typed_args:
7622
7944
  if isinstance(arg.typ, (YearMonthIntervalType, DayTimeIntervalType)):
7623
- raise NotImplementedError(
7945
+ exception = NotImplementedError(
7624
7946
  "try_add with interval types is not supported"
7625
7947
  )
7948
+ attach_custom_error_code(
7949
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
7950
+ )
7951
+ raise exception
7626
7952
  result_exp = _try_arithmetic_helper(snowpark_typed_args, snowpark_args, 0)
7627
7953
  result_exp = _type_with_typer(result_exp)
7628
7954
  case "try_aes_decrypt":
@@ -7679,9 +8005,13 @@ def map_unresolved_function(
7679
8005
  # Check for interval types and throw NotImplementedError
7680
8006
  for arg in snowpark_typed_args:
7681
8007
  if isinstance(arg.typ, (YearMonthIntervalType, DayTimeIntervalType)):
7682
- raise NotImplementedError(
8008
+ exception = NotImplementedError(
7683
8009
  "try_divide with interval types is not supported"
7684
8010
  )
8011
+ attach_custom_error_code(
8012
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
8013
+ )
8014
+ raise exception
7685
8015
  match (snowpark_typed_args[0].typ, snowpark_typed_args[1].typ):
7686
8016
  case (NullType(), t) | (t, NullType()):
7687
8017
  result_exp = snowpark_fn.lit(None)
@@ -7742,9 +8072,11 @@ def map_unresolved_function(
7742
8072
  ).otherwise(cleaned_left / cleaned_right)
7743
8073
  result_exp = _type_with_typer(result_exp)
7744
8074
  case (_, _):
7745
- raise AnalysisException(
8075
+ exception = AnalysisException(
7746
8076
  f"Incompatible types: {snowpark_typed_args[0].typ}, {snowpark_typed_args[1].typ}"
7747
8077
  )
8078
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8079
+ raise exception
7748
8080
 
7749
8081
  case "try_element_at":
7750
8082
  # For structured ArrayType and MapType columns, Snowflake raises an error when an index is out of bounds or a key does not exist.
@@ -7786,16 +8118,22 @@ def map_unresolved_function(
7786
8118
  case _:
7787
8119
  # Currently we do not handle VariantType columns as the first argument here.
7788
8120
  # Spark will not support VariantType until 4.0.0, revisit this when the support is added.
7789
- raise AnalysisException(
8121
+ exception = AnalysisException(
7790
8122
  f"Expected either (ArrayType, IntegralType) or (MapType, StringType), got {snowpark_typed_args[0].typ}, {snowpark_typed_args[1].typ}."
7791
8123
  )
8124
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8125
+ raise exception
7792
8126
  case "try_multiply":
7793
8127
  # Check for interval types and throw NotImplementedError
7794
8128
  for arg in snowpark_typed_args:
7795
8129
  if isinstance(arg.typ, (YearMonthIntervalType, DayTimeIntervalType)):
7796
- raise NotImplementedError(
8130
+ exception = NotImplementedError(
7797
8131
  "try_multiply with interval types is not supported"
7798
8132
  )
8133
+ attach_custom_error_code(
8134
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
8135
+ )
8136
+ raise exception
7799
8137
  match (snowpark_typed_args[0].typ, snowpark_typed_args[1].typ):
7800
8138
  case (NullType(), t) | (t, NullType()):
7801
8139
  result_exp = snowpark_fn.lit(None)
@@ -7870,9 +8208,11 @@ def map_unresolved_function(
7870
8208
  result_exp = cleaned_left * cleaned_right
7871
8209
  result_exp = _type_with_typer(result_exp)
7872
8210
  case (_, _):
7873
- raise AnalysisException(
8211
+ exception = AnalysisException(
7874
8212
  f"Incompatible types: {snowpark_typed_args[0].typ}, {snowpark_typed_args[1].typ}"
7875
8213
  )
8214
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8215
+ raise exception
7876
8216
  case "try_sum":
7877
8217
  # Snowflake raises an error when a value that cannot be cast into a numeric is passed to SUM. Spark treats these as NULL values and
7878
8218
  # does not throw an error. Additionally, Spark returns NULL when this calculation results in an overflow, whereas Snowflake raises a "TypeError".
@@ -7897,9 +8237,13 @@ def map_unresolved_function(
7897
8237
  # Check for interval types and throw NotImplementedError
7898
8238
  for arg in snowpark_typed_args:
7899
8239
  if isinstance(arg.typ, (YearMonthIntervalType, DayTimeIntervalType)):
7900
- raise NotImplementedError(
8240
+ exception = NotImplementedError(
7901
8241
  "try_subtract with interval types is not supported"
7902
8242
  )
8243
+ attach_custom_error_code(
8244
+ exception, ErrorCodes.UNSUPPORTED_OPERATION
8245
+ )
8246
+ raise exception
7903
8247
  result_exp = _try_arithmetic_helper(snowpark_typed_args, snowpark_args, 1)
7904
8248
  result_exp = _type_with_typer(result_exp)
7905
8249
  case "try_to_number":
@@ -7924,7 +8268,13 @@ def map_unresolved_function(
7924
8268
  ),
7925
8269
  )
7926
8270
  case _:
7927
- raise ValueError(f"Invalid number of arguments to {function_name}")
8271
+ exception = ValueError(
8272
+ f"Invalid number of arguments to {function_name}"
8273
+ )
8274
+ attach_custom_error_code(
8275
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
8276
+ )
8277
+ raise exception
7928
8278
  result_type = get_timestamp_type()
7929
8279
  result_exp = snowpark_fn.cast(result_exp, result_type)
7930
8280
  case "typeof":
@@ -8036,9 +8386,13 @@ def map_unresolved_function(
8036
8386
  snowpark_fn.lit("YYYY-MM-DD HH24:MI:SS"),
8037
8387
  )
8038
8388
  case _:
8039
- raise SnowparkConnectNotImplementedError(
8389
+ exception = SnowparkConnectNotImplementedError(
8040
8390
  "unix_timestamp expected 0, 1 or 2 arguments."
8041
8391
  )
8392
+ attach_custom_error_code(
8393
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
8394
+ )
8395
+ raise exception
8042
8396
  result_type = LongType()
8043
8397
  case "unwrap_udt":
8044
8398
  snowpark_col_name = snowpark_args[0].get_name()
@@ -8055,9 +8409,11 @@ def map_unresolved_function(
8055
8409
  )
8056
8410
 
8057
8411
  if "__udt_info__" not in metadata:
8058
- raise AnalysisException(
8412
+ exception = AnalysisException(
8059
8413
  f"[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve '{spark_function_name})' due to data type mismatch: Parameter 1 requires the 'USERDEFINEDTYPE' type"
8060
8414
  )
8415
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8416
+ raise exception
8061
8417
 
8062
8418
  result_type = map_json_schema_to_snowpark(
8063
8419
  metadata["__udt_info__"]["sqlType"]
@@ -8113,9 +8469,11 @@ def map_unresolved_function(
8113
8469
  snowpark_args[0], DoubleType()
8114
8470
  )
8115
8471
  else:
8116
- raise AnalysisException(
8472
+ exception = AnalysisException(
8117
8473
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{function_name}({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
8118
8474
  )
8475
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8476
+ raise exception
8119
8477
  result_type = DoubleType()
8120
8478
  result_exp = _resolve_aggregate_exp(
8121
8479
  snowpark_fn.var_pop(var_pop_argument), result_type
@@ -8128,9 +8486,11 @@ def map_unresolved_function(
8128
8486
  snowpark_args[0], DoubleType()
8129
8487
  )
8130
8488
  else:
8131
- raise AnalysisException(
8489
+ exception = AnalysisException(
8132
8490
  f"""AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "{function_name}({snowpark_arg_names[0]})" due to data type mismatch: Parameter 1 requires the "DOUBLE" type, however "{snowpark_arg_names[0]}" has the type "{snowpark_typed_args[0].typ}".;"""
8133
8491
  )
8492
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8493
+ raise exception
8134
8494
  result_type = DoubleType()
8135
8495
  result_exp = _resolve_aggregate_exp(
8136
8496
  snowpark_fn.var_samp(var_samp_argument), result_type
@@ -8163,10 +8523,12 @@ def map_unresolved_function(
8163
8523
  if len(snowpark_typed_args) > 0:
8164
8524
  condition_type = snowpark_typed_args[0].typ
8165
8525
  if not isinstance(condition_type, BooleanType):
8166
- raise AnalysisException(
8526
+ exception = AnalysisException(
8167
8527
  f"[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve CASE WHEN condition due to data type mismatch: "
8168
8528
  f"Parameter 1 requires the 'BOOLEAN' type, however got '{condition_type}'"
8169
8529
  )
8530
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8531
+ raise exception
8170
8532
 
8171
8533
  name_components = ["CASE"]
8172
8534
  name_components.append("WHEN")
@@ -8189,10 +8551,12 @@ def map_unresolved_function(
8189
8551
  # Validate each WHEN condition
8190
8552
  condition_type = snowpark_typed_args[i].typ
8191
8553
  if not isinstance(condition_type, BooleanType):
8192
- raise AnalysisException(
8554
+ exception = AnalysisException(
8193
8555
  f"[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve CASE WHEN condition due to data type mismatch: "
8194
8556
  f"Parameter {i + 1} requires the 'BOOLEAN' type, however got '{condition_type}'"
8195
8557
  )
8558
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8559
+ raise exception
8196
8560
  result_exp = result_exp.when(snowpark_args[i], snowpark_args[i + 1])
8197
8561
  result_type_indexes.append(i + 1)
8198
8562
  name_components.append("END")
@@ -8429,9 +8793,11 @@ def map_unresolved_function(
8429
8793
  # TODO: Add more here as we come across them.
8430
8794
  # Unfortunately the scope of function names are not documented in
8431
8795
  # the proto file.
8432
- raise SnowparkConnectNotImplementedError(
8796
+ exception = SnowparkConnectNotImplementedError(
8433
8797
  f"Unsupported function name {other}"
8434
8798
  )
8799
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
8800
+ raise exception
8435
8801
 
8436
8802
  def _to_typed_column(
8437
8803
  res: Column | TypedColumn,
@@ -8446,9 +8812,11 @@ def map_unresolved_function(
8446
8812
  # 1. Static type: Assign directly to `result_type` when type is known at resolve time
8447
8813
  # 2. Dynamic type based on function arguments types: Use `snowpark_typed_args` to determine type
8448
8814
  # 3. Use _type_with_typer() as last resort - it calls GS to determine the type
8449
- raise SnowparkConnectNotImplementedError(
8815
+ exception = SnowparkConnectNotImplementedError(
8450
8816
  f"Result type of function {function_name} not implemented"
8451
8817
  )
8818
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
8819
+ raise exception
8452
8820
  elif type(res_type) is list:
8453
8821
  tc = TypedColumn(res, lambda: res_type)
8454
8822
  else:
@@ -8534,15 +8902,19 @@ def _extract_window_args(fn: expressions_proto.Expression) -> (str, str):
8534
8902
  args = fn.unresolved_function.arguments
8535
8903
  match args:
8536
8904
  case [_, _, _]:
8537
- raise SnowparkConnectNotImplementedError(
8905
+ exception = SnowparkConnectNotImplementedError(
8538
8906
  "the slide_duration parameter is not supported"
8539
8907
  )
8908
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
8909
+ raise exception
8540
8910
  case [_, window_duration, slide_duration, _] if unwrap_literal(
8541
8911
  window_duration
8542
8912
  ) != unwrap_literal(slide_duration):
8543
- raise SnowparkConnectNotImplementedError(
8913
+ exception = SnowparkConnectNotImplementedError(
8544
8914
  "the slide_duration parameter is not supported"
8545
8915
  )
8916
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
8917
+ raise exception
8546
8918
  case [_, window_duration, _, start_time]:
8547
8919
  return unwrap_literal(window_duration), unwrap_literal(start_time)
8548
8920
  case [_, window_duration]:
@@ -8610,7 +8982,9 @@ def _find_common_type(
8610
8982
  typ = _common(type1.element_type, type2.element_type)
8611
8983
  return ArrayType(typ)
8612
8984
  case (ArrayType(), _) | (_, ArrayType()) if func_name == "concat":
8613
- raise AnalysisException(exception_base_message)
8985
+ exception = AnalysisException(exception_base_message)
8986
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
8987
+ raise exception
8614
8988
  case (NullType(), t) | (t, NullType()):
8615
8989
  return t
8616
8990
  case (BinaryType(), BinaryType()):
@@ -8639,7 +9013,9 @@ def _find_common_type(
8639
9013
  if [field.name for field in fields1] != [
8640
9014
  field.name for field in fields2
8641
9015
  ]:
8642
- raise AnalysisException(exception_base_message)
9016
+ exception = AnalysisException(exception_base_message)
9017
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
9018
+ raise exception
8643
9019
  fields = []
8644
9020
  for idx, field in enumerate(fields1):
8645
9021
  typ = _common(field.datatype, fields2[idx].datatype)
@@ -8650,7 +9026,9 @@ def _find_common_type(
8650
9026
  value_type = _common(type1.value_type, type2.value_type)
8651
9027
  return MapType(key_type, value_type)
8652
9028
  case _:
8653
- raise AnalysisException(exception_base_message)
9029
+ exception = AnalysisException(exception_base_message)
9030
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
9031
+ raise exception
8654
9032
 
8655
9033
  types = list(filter(lambda tp: tp is not None, types))
8656
9034
  if not types:
@@ -8663,7 +9041,9 @@ def _find_common_type(
8663
9041
  func_name_message = f" to `{func_name}`" if func_name else ""
8664
9042
  types_message = " or ".join([f'"{type}"' for type in types])
8665
9043
  exception_message = f"{exception_base_message} Cannot resolve expression due to data type mismatch: Input{func_name_message} should all be the same type, but it's ({types_message})."
8666
- raise AnalysisException(exception_message)
9044
+ exception = AnalysisException(exception_message)
9045
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
9046
+ raise exception
8667
9047
  else:
8668
9048
  raise
8669
9049
 
@@ -8821,7 +9201,9 @@ def _resolve_function_with_lambda(
8821
9201
  case ArrayType():
8822
9202
  return VariantType()
8823
9203
  case t:
8824
- raise ValueError(f"Expected array, got {t}")
9204
+ exception = ValueError(f"Expected array, got {t}")
9205
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
9206
+ raise exception
8825
9207
 
8826
9208
  def _get_map_types(tc: TypedColumn):
8827
9209
  match tc.typ:
@@ -8830,9 +9212,11 @@ def _resolve_function_with_lambda(
8830
9212
  case MapType():
8831
9213
  return VariantType(), VariantType()
8832
9214
  case t:
8833
- raise AnalysisException(
9215
+ exception = AnalysisException(
8834
9216
  f'[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Parameter 1 requires the "MAP" type, however "id" has the type "{t}".'
8835
9217
  )
9218
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
9219
+ raise exception
8836
9220
 
8837
9221
  def _map_to_array(m: dict) -> Optional[list]:
8838
9222
  # confirm that m is a dict and not a sqlNullWrapper
@@ -8898,9 +9282,13 @@ def _resolve_function_with_lambda(
8898
9282
  result_type = arg4_tc.typ # it's type of 'finish' lambda body
8899
9283
  result_exp = snowpark_fn.get(result_exp, snowpark_fn.lit(0))
8900
9284
  case _:
8901
- raise SnowparkConnectNotImplementedError(
9285
+ exception = SnowparkConnectNotImplementedError(
8902
9286
  f"{function_name} function requires 3 or 4 arguments"
8903
9287
  )
9288
+ attach_custom_error_code(
9289
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
9290
+ )
9291
+ raise exception
8904
9292
 
8905
9293
  snowpark_arg_names = [
8906
9294
  arg1_name,
@@ -9124,9 +9512,13 @@ def _resolve_function_with_lambda(
9124
9512
  f"lambdafunction({lambda_body_name}, namedlambdavariable(), namedlambdavariable())",
9125
9513
  ]
9126
9514
  case _:
9127
- raise SnowparkConnectNotImplementedError(
9515
+ exception = SnowparkConnectNotImplementedError(
9128
9516
  f"{function_name} function requires lambda function with 1 or 2 arguments"
9129
9517
  )
9518
+ attach_custom_error_code(
9519
+ exception, ErrorCodes.INVALID_FUNCTION_ARGUMENT
9520
+ )
9521
+ raise exception
9130
9522
  case "transform_keys":
9131
9523
  _map_to_array_udf = cached_udf(
9132
9524
  _map_to_array,
@@ -9280,9 +9672,11 @@ def _resolve_function_with_lambda(
9280
9672
  result_exp = TypedColumn(result_exp, lambda: [ArrayType(fn_body.typ)])
9281
9673
  case other:
9282
9674
  # TODO: Add more here as we come across them.
9283
- raise SnowparkConnectNotImplementedError(
9675
+ exception = SnowparkConnectNotImplementedError(
9284
9676
  f"Unsupported function name {other}"
9285
9677
  )
9678
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
9679
+ raise exception
9286
9680
 
9287
9681
  spark_function_name = f"{function_name}({', '.join(snowpark_arg_names)})"
9288
9682
  if not isinstance(result_exp, TypedColumn):
@@ -9847,9 +10241,11 @@ def _try_arithmetic_helper(
9847
10241
  ) or (
9848
10242
  isinstance(arg2, DateType) and not isinstance(arg1, _IntegralType)
9849
10243
  ):
9850
- raise AnalysisException(
10244
+ exception = AnalysisException(
9851
10245
  '[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "date_add(dt, add)" due to data type mismatch: Parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT") type'
9852
10246
  )
10247
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10248
+ raise exception
9853
10249
  args = (
9854
10250
  snowpark_args[::-1]
9855
10251
  if isinstance(arg1, _IntegralType)
@@ -9872,9 +10268,11 @@ def _try_arithmetic_helper(
9872
10268
  elif isinstance(arg1, DateType) and isinstance(arg2, DateType):
9873
10269
  return snowpark_fn.daydiff(snowpark_args[0], snowpark_args[1])
9874
10270
  else:
9875
- raise AnalysisException(
10271
+ exception = AnalysisException(
9876
10272
  '[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "date_sub(dt, sub)" due to data type mismatch: Parameter 1 requires the "DATE" type and parameter 2 requires the ("INT" or "SMALLINT" or "TINYINT") type'
9877
10273
  )
10274
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10275
+ raise exception
9878
10276
  case (DecimalType(), _IntegralType()) | (_IntegralType(), DecimalType()) | (
9879
10277
  DecimalType(),
9880
10278
  DecimalType(),
@@ -9926,9 +10324,11 @@ def _try_arithmetic_helper(
9926
10324
  return updated_args[0] - updated_args[1]
9927
10325
 
9928
10326
  case (BooleanType(), _) | (_, BooleanType()):
9929
- raise AnalysisException(
10327
+ exception = AnalysisException(
9930
10328
  f"Incompatible types: {typed_args[0].typ}, {typed_args[1].typ}"
9931
10329
  )
10330
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10331
+ raise exception
9932
10332
  case _:
9933
10333
  # Return NULL for incompatible types
9934
10334
  return snowpark_fn.lit(None)
@@ -9968,15 +10368,19 @@ def _get_add_sub_result_type(
9968
10368
  )
9969
10369
  case _:
9970
10370
  if global_config.spark_sql_ansi_enabled:
9971
- raise AnalysisException(
10371
+ exception = AnalysisException(
9972
10372
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("NUMERIC" or "INTERVAL DAY TO SECOND" or "INTERVAL YEAR TO MONTH" or "INTERVAL"), not "STRING".',
9973
10373
  )
10374
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10375
+ raise exception
9974
10376
  else:
9975
10377
  result_type = DoubleType()
9976
10378
  case BooleanType():
9977
- raise AnalysisException(
10379
+ exception = AnalysisException(
9978
10380
  f'[DATATYPE_MISMATCH.BINARY_OP_WRONG_TYPE] Cannot resolve "{spark_function_name}" due to data type mismatch: the binary operator requires the input type ("NUMERIC" or "INTERVAL DAY TO SECOND" or "INTERVAL YEAR TO MONTH" or "INTERVAL"), not "BOOLEAN".',
9979
10381
  )
10382
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10383
+ raise exception
9980
10384
  return result_type, overflow_possible
9981
10385
 
9982
10386
 
@@ -10039,9 +10443,11 @@ def _check_interval_string_comparison(
10039
10443
  else interval_name
10040
10444
  )
10041
10445
 
10042
- raise AnalysisException(
10446
+ exception = AnalysisException(
10043
10447
  f'[DATATYPE_MISMATCH.BINARY_OP_DIFF_TYPES] Cannot resolve "({snowpark_arg_names[0]} {operator} {snowpark_arg_names[1]})" due to data type mismatch: the left and right operands of the binary operator have incompatible types ("{left_type}" and "{right_type}").;'
10044
10448
  )
10449
+ attach_custom_error_code(exception, ErrorCodes.TYPE_MISMATCH)
10450
+ raise exception
10045
10451
 
10046
10452
 
10047
10453
  def _get_spark_function_name(
@@ -10177,12 +10583,18 @@ def _timestamp_format_sanity_check(ts_value: str, ts_format: str) -> None:
10177
10583
  This is a basic validation to ensure the format matches the string.
10178
10584
  """
10179
10585
  if "yyyyyyy" in ts_format:
10180
- raise DateTimeException(
10586
+ exception = DateTimeException(
10181
10587
  f"Fail to recognize '{ts_format}' pattern in the DateTimeFormatter."
10182
10588
  )
10589
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10590
+ raise exception
10183
10591
  if ts_format == "yy":
10184
10592
  if len(ts_value) != 2:
10185
- raise DateTimeException(f"Fail to parse '{ts_value}' in DateTimeFormatter.")
10593
+ exception = DateTimeException(
10594
+ f"Fail to parse '{ts_value}' in DateTimeFormatter."
10595
+ )
10596
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10597
+ raise exception
10186
10598
 
10187
10599
  # For parsing, the acceptable fraction length can be [1, the number of contiguous 'S']
10188
10600
  s_contiguous = 0
@@ -10199,7 +10611,11 @@ def _timestamp_format_sanity_check(ts_value: str, ts_format: str) -> None:
10199
10611
  char_count += 1
10200
10612
 
10201
10613
  if s_contiguous + sum(x.isalnum() for x in ts_value) < char_count:
10202
- raise DateTimeException(f"Fail to parse '{ts_value}' in DateTimeFormatter.")
10614
+ exception = DateTimeException(
10615
+ f"Fail to parse '{ts_value}' in DateTimeFormatter."
10616
+ )
10617
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10618
+ raise exception
10203
10619
 
10204
10620
 
10205
10621
  def _bounded_long_floor_expr(expr):
@@ -10326,17 +10742,21 @@ def _validate_number_format_string(format_str: str) -> None:
10326
10742
  """
10327
10743
 
10328
10744
  def _unexpected_char(char):
10329
- raise AnalysisException(
10745
+ exception = AnalysisException(
10330
10746
  f"[INVALID_FORMAT.UNEXPECTED_TOKEN] The format is invalid: '{original_format}'. "
10331
10747
  f"Found the unexpected character '{char}' in the format string; "
10332
10748
  "the structure of the format string must match: "
10333
10749
  "`[MI|S]` `[$]` `[0|9|G|,]*` `[.|D]` `[0|9]*` `[$]` `[PR|MI|S]`."
10334
10750
  )
10751
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10752
+ raise exception
10335
10753
 
10336
10754
  if not format_str:
10337
- raise AnalysisException(
10755
+ exception = AnalysisException(
10338
10756
  "[INVALID_FORMAT.EMPTY] The format is invalid: ''. The number format string cannot be empty."
10339
10757
  )
10758
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10759
+ raise exception
10340
10760
 
10341
10761
  # Create a working copy of the format string
10342
10762
  remaining = format_str
@@ -10412,9 +10832,11 @@ def _validate_number_format_string(format_str: str) -> None:
10412
10832
  _unexpected_char(char)
10413
10833
 
10414
10834
  # If no invalid character found but no digits, it's still invalid
10415
- raise AnalysisException(
10835
+ exception = AnalysisException(
10416
10836
  f"[INVALID_FORMAT.WRONG_NUM_DIGIT] The format is invalid: '{format_str}'. The format string requires at least one number digit."
10417
10837
  )
10838
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
10839
+ raise exception
10418
10840
 
10419
10841
 
10420
10842
  def _trim_helper(value: Column, trim_value: Column, trim_type: Column) -> Column: