Skip to content

Generator fabricates list-response JSON wrapper tags from parseSingular(), causing recurring silent-nil-slice bugs #155

@jmsperu

Description

@jmsperu

Splitting this out as the systemic root cause behind a recurring class of bugs (#135, #136 / #137, and the four just fixed in #154).

Problem

For List<X>Response structs, generate.go derives the JSON wrapper tag from strings.ToLower(parseSingular(listName)). But the key CloudStack actually returns is set server-side via setObjectName(...), and it is frequently not what parseSingular produces:

  • camelCase: listHypervisorCapabilities → server hypervisorCapabilities, generator hypervisorcapability
  • -xes plural: …Ipv6PrefixesPrefixe (also corrupts the element type name), server guestnetworkipv6prefix
  • hand-chosen keys: listLBHealthCheckPolicies → server healthcheckpolicies (drops the lb, stays plural), generator lbhealthcheckpolicy

When the tag is wrong, json.Unmarshal populates Count but leaves the slice nil — silent data loss — and the generated Get<X>ByID helper then panics on slice[0].

Current mitigation doesn’t scale

generateResponseType already carries a hand-maintained override switch (~30 cases, incl. the metrics ones) that exists precisely to patch this. Each new case is added reactively, only after a user hits a nil slice. #154 adds four more; there are almost certainly others not yet reported.

Note: listApis.json (the generator input) does not expose the list wrapper object name — it carries each item’s response fields and related, but not the setObjectName value — so the correct key can’t simply be read from there.

Proposed directions

  1. Harden parseSingular for the regular English plurals it currently mishandles — -xes/-ses/-ches/-shes → drop es (it already does -ies/-sses). This fixes the Prefixe type-name corruption and several tags for free, shrinking the override set.
  2. Make the override set verifiable instead of reactive: add a CI/test check that asserts each List<X>Response tag against the keys in the test/testdata/*.json fixtures (and/or a captured real response), so drift is caught at build time rather than by users in production.
  3. Optionally, a curated command → objectName override map (cleaner than inline switch cases) seeded from the verified keys.

I verified the #154 keys against the CloudStack server source (setObjectName) and have a 4.22 environment; happy to take on (1) and/or (2) if a maintainer signals a preferred direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions