Skip to content

MerakiClient constructor omits organization Refit clients used by Dashboard API; IOrganizationsWirelessDevicesChannelUtilization fails Refit build #337

Description

@pjorritsma

Title

MerakiClient constructor omits organization Refit clients used by Dashboard API; IOrganizationsWirelessDevicesChannelUtilization fails Refit build


Body

Environment

  • Package: Meraki.Api 1.70.5
  • Target: .NET 9.0
  • Consumer: internal DataHub sync service (Cisco Meraki Dashboard API v1)

Summary

Several organization-level API clients that exist in the SDK surface area are never assigned in the MerakiClient constructor. They remain null after new MerakiClient(...), which causes NullReferenceException when calling methods such as GetOrganizationSummarySwitchPowerHistoryAsync.

Additionally, IOrganizationsWirelessDevicesChannelUtilization cannot be instantiated via the library’s own RefitFor<T>() helper because of a Refit route/parameter name mismatch.

Expected behavior

After constructing MerakiClient with valid options, all public section properties that expose Refit interfaces should be initialized the same way as Organizations.Summary.Top, Organizations.SwitchPortsOverview, and Organizations.Uplinks.

Actual behavior

On a fresh client (API key can be a dummy string — wiring happens in the ctor):

Path Initialized?
Organizations.Summary.Top Yes
Organizations.SwitchPortsOverview Yes
Organizations.Summary.SwitchPower No (null)
Organizations.Appliance.Uplinks.Usage No (null)
Organizations.Wireless.Devices.Latency No (null)
Organizations.Wireless.Devices.PacketLoss No (null)
Organizations.Wireless.Devices.ChannelUtilization No (null)

Organizations.Appliance and Organizations.Wireless sections are never populated in the constructor’s Organizations = new OrganizationsSection { ... } initializer (only Summary.Top is set under Summary).

Minimal reproduction

using Meraki.Api;

var client = new MerakiClient(new MerakiClientOptions
{
    ApiKey = "0000000000000000000000000000000000000000",
    UserAgent = "Repro/1.0"
});

Console.WriteLine(client.Organizations.Summary.SwitchPower is null);           // True
Console.WriteLine(client.Organizations.Appliance.Uplinks.Usage is null);        // True
Console.WriteLine(client.Organizations.Wireless.Devices.Latency is null);     // True
Console.WriteLine(client.Organizations.Wireless.Devices.PacketLoss is null);  // True
Console.WriteLine(client.Organizations.Wireless.Devices.ChannelUtilization is null); // True

Calling any method on the null clients throws NullReferenceException, e.g.:

await client.Organizations.Summary.SwitchPower!
    .GetOrganizationSummarySwitchPowerHistoryAsync("123456", "2026-01-01T00:00:00Z", "2026-01-02T00:00:00Z");

Root cause (constructor)

In MerakiClient, organization summary is only partially wired:

Summary = new()
{
    Top = RefitFor(Organizations.Summary.Top)
    // SwitchPower is never assigned
},

There is no initializer block for Appliance = new() { Uplinks = new() { Usage = RefitFor(...) } } or Wireless = new() { Devices = new() { Latency = ..., PacketLoss = ... } } under OrganizationsSection.

Official API endpoints (for reference):

Separate bug: IOrganizationsWirelessDevicesChannelUtilization

Even when creating the client via the library’s private RefitFor<T>() (same path as other endpoints), instantiation fails:

ArgumentException: URL /organizations/{organizationId}/wireless/devices/channelUtilization/byDevice
has parameter organizationid, but no method parameter matches

So the interface cannot be used at all in 1.70.5 until the Refit route template or method parameter names are aligned (likely organizationId vs organizationid).

Suggested fix

  1. In MerakiClient constructor, extend the Organizations initializer, for example:
Appliance = new()
{
    Uplinks = new()
    {
        Usage = RefitFor(Organizations.Appliance.Uplinks.Usage)
    }
},
Wireless = new()
{
    Devices = new()
    {
        Latency = RefitFor(Organizations.Wireless.Devices.Latency),
        PacketLoss = RefitFor(Organizations.Wireless.Devices.PacketLoss),
        ChannelUtilization = RefitFor(Organizations.Wireless.Devices.ChannelUtilization),
    }
},
Summary = new()
{
    Top = RefitFor(Organizations.Summary.Top),
    SwitchPower = RefitFor(Organizations.Summary.SwitchPower),
},
  1. Fix the Refit attribute/parameter naming on IOrganizationsWirelessDevicesChannelUtilization so RefitFor succeeds.

Consumer workaround (until fixed)

We currently call the private RefitFor<T>() via reflection for the four interfaces that can be created, and skip channel utilization sync with a log line. We would prefer to remove this once the package is fixed.


Optional labels (if available)

bug, MerakiClient, organizations

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions