C · recipe

Decode custom structures in C

open62541 can read a server's DataTypeDefinitions at runtime, but in C the pragmatic path for a known model is to generate types at build time from a NodeSet2 file. Runtime decoding of an unknown structure means walking the ExtensionObject yourself.

Stackopen62541
Version1.5.8

The code

#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <stdio.h>

int main(void) {
    UA_Client *client = UA_Client_new();
    UA_ClientConfig_setDefault(UA_Client_getConfig(client));
    if (UA_Client_connect(client, "opc.tcp://opcua.umati.app:4840") != UA_STATUSCODE_GOOD) {
        UA_Client_delete(client); return 1;
    }

    UA_Variant v;
    UA_Variant_init(&v);
    UA_StatusCode rc = UA_Client_readValueAttribute(
        client, UA_NODEID_NUMERIC(4, 7001), &v);

    if (rc == UA_STATUSCODE_GOOD &&
        v.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
        UA_ExtensionObject *eo = (UA_ExtensionObject *)v.data;
        if (eo->encoding == UA_EXTENSIONOBJECT_DECODED) {
            printf("decoded, type: %s\n", eo->content.decoded.type->typeName);
            /* cast eo->content.decoded.data to the generated struct */
        } else {
            printf("still encoded: %zu bytes of body\n",
                   eo->content.encoded.body.length);
            printf("-> the type is not known to this client\n");
        }
    }
    UA_Variant_clear(&v);

    UA_Client_disconnect(client);
    UA_Client_delete(client);
    return 0;
}

/* Preferred for a known model: generate types at build time.
   open62541 ships generators that turn a NodeSet2 XML file into C structs
   and the matching data type array, which you then register on the client. */

What it prints

still encoded: 48 bytes of body
-> the type is not known to this client

# after registering generated types for the model:
# decoded, type: ProductionJobType

Notes

  • In C, prefer build-time generation from the NodeSet2 file when the model is known and stable. It gives you real structs and no runtime type machinery.
  • An ExtensionObject with encoding UA_EXTENSIONOBJECT_ENCODED_BYTESTRING means the client does not know the type. That is information, not a failure.
  • Runtime decoding of arbitrary structures in C is possible but rarely worth it on an embedded target. If you need it, consider whether that component belongs in C at all.
  • Unions and optional fields are where generated decoders break. Test them against real server data.

What breaks first

The structure never decodes and you only ever see bytes BadDataEncodingUnsupported
Register the type with the client, either from generated build-time types or by loading the server's DataTypeDefinitions.
Other recipes in this stack

Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.

Free download
OPC UA Troubleshooting & Integration Checklist
The field-tested checklist engineers use to diagnose certificates, ports and namespace problems fast, plus a Python (asyncua) client template.
Get the free checklist →
Free, no course, no login