diff --git a/ingestion/src/metadata/ingestion/ometa/mixins/patch_mixin.py b/ingestion/src/metadata/ingestion/ometa/mixins/patch_mixin.py index 38fbf0f24572..dc8b5b9c0c12 100644 --- a/ingestion/src/metadata/ingestion/ometa/mixins/patch_mixin.py +++ b/ingestion/src/metadata/ingestion/ometa/mixins/patch_mixin.py @@ -65,6 +65,24 @@ OWNER_TYPES: List[str] = ["user", "team"] # noqa: UP006 +def _summarize_patch(patch: Any) -> str: + """Return op count and `op:path` list for a JSON Patch, without values. + + Values are intentionally excluded — they may contain descriptions, sample + data, or tag content that should not be logged. + """ + if patch is None: + return "" + try: + ops = json.loads(str(patch)) + except (ValueError, TypeError): + return "" + if not isinstance(ops, list): + return "" + op_paths = [f"{op.get('op', '?')}:{op.get('path', '?')}" for op in ops if isinstance(op, dict)] + return f"{len(ops)} op(s) [{', '.join(op_paths)}]" + + def convert_uuids_to_strings(obj: Any) -> Any: """ Recursively convert UUID objects to strings for JSON serialization @@ -169,6 +187,7 @@ def patch( # pylint: disable=too-many-arguments Returns Updated Entity """ + patch = None try: patch = build_patch( source=source, @@ -191,16 +210,19 @@ def patch( # pylint: disable=too-many-arguments except Exception as exc: logger.debug(traceback.format_exc()) + patch_summary = _summarize_patch(patch) + entity_name = get_log_name(source) if skip_on_failure: - entity_name = get_log_name(source) - logger.warning(f"Failed to update {entity_name}. The patch operation was skipped. Reason: {exc}") + logger.warning( + f"Failed to update {entity_name}. The patch operation was skipped. " + f"Reason: {exc} | Patch ops: {patch_summary}" + ) return None - else: # noqa: RET505 - entity_name = get_log_name(source) - raise RuntimeError( - f"Failed to update {entity_name}. The patch operation failed. " - f"Set 'skip_on_failure=True' to skip failed patches. Error: {exc}" - ) from exc + raise RuntimeError( + f"Failed to update {entity_name}. The patch operation failed. " + f"Set 'skip_on_failure=True' to skip failed patches. " + f"Error: {exc} | Patch ops: {patch_summary}" + ) from exc def patch_description( self, diff --git a/openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java b/openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java index 30c0069124ff..c511b9ab4511 100644 --- a/openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java +++ b/openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java @@ -412,7 +412,8 @@ public static T applyPatch(T original, JsonPatch patch, Class clz) { JsonNode jsonNode = OBJECT_MAPPER.readTree(jsonString); return OBJECT_MAPPER.convertValue(jsonNode, clz); } catch (Exception e) { - throw new RuntimeException("Failed to convert JsonValue to target class", e); + throw new RuntimeException( + "Failed to convert JsonValue to " + clz.getSimpleName() + ": " + e.getMessage(), e); } }