Skip to content

Conversation

mihainradu
Copy link
Collaborator

StandardError, UiPath.ErrorInfo.Error, travels under Exception.Data["UiPath.ErrorInfo.Error"]
In order to have it bubble up from inside the system we need to make sure it is marshaled from server to client
Servers have the option to decide which data fields should be marshaled, yet ErrorInfo is in the default list

Copilot

This comment was marked as outdated.

@mihainradu mihainradu changed the title add support for standardError propagation [wip] add support for standardError propagation Aug 6, 2025
@mihainradu mihainradu force-pushed the feat/mr-propagate-exception-data branch 2 times, most recently from a7cf0e2 to 7a175c0 Compare August 6, 2025 18:33
@mihainradu mihainradu changed the base branch from master to support/v21.10 August 6, 2025 18:36
@mihainradu mihainradu changed the base branch from support/v21.10 to master August 6, 2025 18:38
@mihainradu mihainradu force-pushed the feat/mr-propagate-exception-data branch 2 times, most recently from facfde4 to eb085c0 Compare August 6, 2025 18:51
@mihainradu mihainradu changed the title [wip] add support for standardError propagation [wip] add support for Exception.Data propagation Aug 6, 2025
@mihainradu mihainradu requested a review from Copilot August 6, 2025 18:52
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for propagating Exception.Data across IPC boundaries by extending the Error record to include a Data property and providing mechanisms for selective serialization of exception data.

  • Extends the Error record to include serializable exception data with a configurable whitelist
  • Adds an OnError handler mechanism for server-side exception processing
  • Implements marshalling/unmarshalling of exception data between RemoteException and Error objects

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/UiPath.CoreIpc/Wire/Dtos.cs Core implementation of exception data serialization with configurable key filtering
src/UiPath.CoreIpc/Server/Server.cs Server-side error handling with OnError callback invocation
src/UiPath.CoreIpc/Server/ContractSettings.cs Configuration for OnError handler in contract settings
src/UiPath.CoreIpc/Helpers/Router.cs Route configuration to include OnError handler
src/UiPath.CoreIpc/Helpers/Helpers.cs Simplified error conversion to use centralized Error.FromException
src/UiPath.CoreIpc.Tests/TestBase.cs Test infrastructure for OnError handler testing
src/UiPath.CoreIpc.Tests/SystemTests.cs Test cases for exception data marshalling functionality
src/UiPath.CoreIpc.Tests/Services/SystemService.cs Test service method for exception data scenarios
src/UiPath.CoreIpc.Tests/Services/ISystemService.cs Interface definition for test service method
Comments suppressed due to low confidence (1)

{
foreach (var key in error.Data)
{
Data[key.Key] = IpcJsonSerializer.Instance.Deserialize(key.Value, typeof(object));
Copy link
Preview

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deserializing to typeof(object) without type validation could lead to security vulnerabilities through object injection attacks. Consider implementing type validation or using a safer deserialization approach.

Suggested change
Data[key.Key] = IpcJsonSerializer.Instance.Deserialize(key.Value, typeof(object));
Data[key.Key] = SafeParsePrimitiveOrString(key.Value);

Copilot uses AI. Check for mistakes.

Comment on lines 156 to 170
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);

_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};

var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
Copy link
Preview

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying a static collection in a test can cause test interference and unpredictable results. Consider using a test-specific configuration or restoring the original state in test cleanup.

Suggested change
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);
_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};
var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
var originalSerializableDataKeys = Error.SerializableDataKeys.ToList();
try
{
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);
_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};
var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
}
finally
{
Error.SerializableDataKeys.Clear();
foreach (var key in originalSerializableDataKeys)
{
Error.SerializableDataKeys.Add(key);
}
}

Copilot uses AI. Check for mistakes.

Comment on lines 156 to 170
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);

_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};

var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
Copy link
Preview

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing items from a static collection in a test can affect other tests. This could cause tests to behave differently when run in isolation versus as part of a suite.

Suggested change
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);
_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};
var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
var originalSerializableDataKeys = Error.SerializableDataKeys.ToList();
try
{
Error.SerializableDataKeys.Add(InlineDataKey);
Error.SerializableDataKeys.Add(OnErrorDataKey);
Error.SerializableDataKeys.Remove(notSerialized);
_onError = (callInfo, ex) =>
{
ex.Data.Add(OnErrorDataKey, value);
ex.Data.Add(notSerialized2, value);
return ex;
};
var ex = await Proxy.ThrowWithData(InlineDataKey, value, notSerialized).ShouldThrowAsync<RemoteException>();
ex.Data[InlineDataKey].ShouldBe(value);
ex.Data.Contains(notSerialized).ShouldBeFalse();
ex.Data[OnErrorDataKey].ShouldBe(value);
}
finally
{
Error.SerializableDataKeys.Clear();
foreach (var key in originalSerializableDataKeys)
{
Error.SerializableDataKeys.Add(key);
}
}

Copilot uses AI. Check for mistakes.

if (exception.Data.Contains(key))
{
data ??= [];
data[key] = IpcJsonSerializer.Instance.Serialize(exception.Data[key]);
Copy link
Preview

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The serialization could fail if exception.Data[key] contains non-serializable objects. Consider adding exception handling or type validation before serialization.

Suggested change
data[key] = IpcJsonSerializer.Instance.Serialize(exception.Data[key]);
try
{
data[key] = IpcJsonSerializer.Instance.Serialize(exception.Data[key]);
}
catch (Exception serializeEx)
{
var valueType = exception.Data[key]?.GetType().FullName ?? "null";
data[key] = $"<Non-serializable object of type '{valueType}': {serializeEx.Message}>";
}

Copilot uses AI. Check for mistakes.

@mihainradu mihainradu force-pushed the feat/mr-propagate-exception-data branch from eb085c0 to f4bc134 Compare August 7, 2025 09:35
@mihainradu mihainradu force-pushed the feat/mr-propagate-exception-data branch from f4bc134 to 361d233 Compare August 7, 2025 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant