Skip to content

Fix InvalidCastException in GetBrowseName methods for Attributes, DataTypes, ReferenceTypes, and StatusCodes#3242

Merged
marcschier merged 3 commits into
masterfrom
copilot/fix-invalid-cast-exception
Oct 8, 2025
Merged

Fix InvalidCastException in GetBrowseName methods for Attributes, DataTypes, ReferenceTypes, and StatusCodes#3242
marcschier merged 3 commits into
masterfrom
copilot/fix-invalid-cast-exception

Conversation

Copilot AI commented Oct 7, 2025

Copy link
Copy Markdown
Contributor

Description

Fixes #2434 - Resolves InvalidCastException when calling GetBrowseName() methods on various constant classes.

Problem

The GetBrowseName() methods in Attributes, DataTypes, ReferenceTypes, and StatusCodes classes were throwing InvalidCastException when retrieving field values via reflection:

// This would throw: Unable to cast object of type 'System.Int32' to type 'System.UInt32'
string attributeBrowseName = Attributes.GetBrowseName(Attributes.Value);

Root Cause: When using reflection to retrieve const uint field values, field.GetValue() returns a boxed object. For values within the int range, the value is boxed as int rather than uint. Direct casting (uint)field.GetValue() throws an exception because you cannot directly cast a boxed int to uint.

Solution

  1. Use Convert.ToUInt32(): Replace direct casts with Convert.ToUInt32(field.GetValue(...), CultureInfo.InvariantCulture) to properly handle the boxed value conversion.

  2. Add type filtering: Include if (field.FieldType == typeof(uint)) checks to only process uint fields, avoiding potential issues with other static fields.

  3. Code style compliance: Split long lines to meet the 160-character limit.

Changes

Fixed Classes

  • Attributes.Helpers.cs - Fixed s_attributesIdToName dictionary initialization
  • DataTypes.Helpers.cs - Fixed s_dataTypeIdToName dictionary initialization
  • ReferenceTypes.Helpers.cs - Fixed s_referenceTypeIdToName dictionary initialization
  • StatusCodes.Helpers.cs - Fixed both s_statusCodeToSymbol and s_utf8BrowseNames dictionary initializations
  • Utils.cs - Fixed generic GetIdentifier() helper method
  • DataGenerator.cs - Fixed StatusCode field reflection

Tests Added

Added comprehensive unit tests covering all fixed methods:

  • AttributesTests.cs - 7 tests for Attributes class
  • DataTypesTests.cs - 7 tests for DataTypes class
  • ReferenceTypesTests.cs - 7 tests for ReferenceTypes class
  • StatusCodesTests.cs - 10 tests for StatusCodes class (including UTF8 encoding)

Total: 31 new tests, all passing

Verification

✅ The exact scenario from the issue now works correctly
✅ All 31 new unit tests pass
✅ All 24,571 existing core tests pass (no regressions)
✅ Tested on .NET 8.0 as specified in the issue

Example Usage

// All of these now work without exceptions:
string attrName = Attributes.GetBrowseName(Attributes.Value);           // "Value"
string dataTypeName = DataTypes.GetBrowseName((int)DataTypes.Boolean);  // "Boolean"
string refTypeName = ReferenceTypes.GetBrowseName(ReferenceTypes.References); // "References"
string statusName = StatusCodes.GetBrowseName(StatusCodes.Good);        // "Good"
Original prompt

This section details on the original issue you should resolve

<issue_title>Getting Attribute BrowseName throws invalid cast exception</issue_title>
<issue_description>### Type of issue

  • Bug
  • Enhancement
  • Compliance
  • Question
  • Help wanted

Current Behavior

The current version of Attributes.GetBrowseName() throws an invalid cast exception even when using e.g. Attributes.Value.
The produced exception is:

System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.UInt32'.
         at Opc.Ua.Attributes.<>c.<.cctor>b__47_1()
         at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
         at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
         at System.Lazy`1.CreateValue()
         at Opc.Ua.Attributes.GetBrowseName(UInt32 identifier)
...

Expected Behavior

The expected behavior is to get the browse name string by using a valid AttributeId.

Steps To Reproduce

string attributeBrowseName = Attributes.GetBrowseName(Attributes.Value);

Environment

- OS: Windows 11
- Environment:
- Runtime: .NET 8 (and .NET 9)
- Nuget Version: 1.5.377.21
- Component: Opc.Ua.Core

Anything else?

No response</issue_description>

<agent_instructions>Add a unit test to test GetBrowseName. Identify other areas with the same pattern and fix.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #3240

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented Oct 7, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.47826% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.75%. Comparing base (9520181) to head (c36a8e2).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
Stack/Opc.Ua.Core/Types/Utils/Utils.cs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3242      +/-   ##
==========================================
+ Coverage   57.68%   57.75%   +0.07%     
==========================================
  Files         361      361              
  Lines       79163    79199      +36     
  Branches    13821    13826       +5     
==========================================
+ Hits        45665    45745      +80     
+ Misses      29275    29220      -55     
- Partials     4223     4234      +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI changed the title [WIP] Fix invalid cast exception in Attributes.GetBrowseName method Fix InvalidCastException in GetBrowseName methods for Attributes, DataTypes, ReferenceTypes, and StatusCodes Oct 7, 2025
Copilot AI requested a review from marcschier October 7, 2025 09:25
@marcschier
marcschier marked this pull request as ready for review October 7, 2025 10:18
@marcschier

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@marcschier
marcschier merged commit 59c7458 into master Oct 8, 2025
119 of 120 checks passed
@marcschier
marcschier deleted the copilot/fix-invalid-cast-exception branch October 8, 2025 07:45
@iconics-janb

Copy link
Copy Markdown

Thanks for fixing this! When do you plan to publish an updated NuGet package?

@romanett

Copy link
Copy Markdown
Contributor

@iconics-janb It will take some more weeks at least

@heidva

heidva commented Nov 18, 2025

Copy link
Copy Markdown

I’ve noticed that in the latest NuGet release (1.5.377.22), the fix still hasn’t been included.
Could you clarify why this is the case? Is there a timeline or plan for when the fix will be released?

@romanett

Copy link
Copy Markdown
Contributor

@heidva there will be a new Release to nuget in the coming days (still labeled Preview) that includes the fix. In the meantime you could use the Preview nuget Feed linked in the Main readme.

@romanett

Copy link
Copy Markdown
Contributor

@heidva 1.5.378-preview is released

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

7 participants