Skip to content

Accept a null errorCode instead of losing the whole device - #131

Merged
eman merged 2 commits into
mainfrom
fix/null-error-code
Sep 1, 2026
Merged

Accept a null errorCode instead of losing the whole device#131
eman merged 2 commits into
mainfrom
fix/null-error-code

Conversation

@eman

@eman eman commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Fixes #130 — reported downstream as eman/ha_nwp500#131.

The cloud returns "error": {"errorCode": null} on some devices. DeviceErrorSummary.error_code, added in 9.3.1 (#124), is typed ErrorCode | int with union_mode="left_to_right"; neither branch accepts None, so a null fails validation of the entire Device and takes the whole /device/list response with it. Downstream the device simply disappears and the Home Assistant integration cannot set up:

Error communicating with API: 2 validation errors for Device
error.errorCode.int-enum[ErrorCode]
  Input should be 0, 96, 97, 326, ... or 990 [type=enum, input_value=None, input_type=NoneType]
error.errorCode.int
  Input should be a valid integer [type=int_type, input_value=None, input_type=NoneType]

Every other field added alongside it (errorOccuredTime, the descaling timestamps, modelTypeCode, installerId) is already null-tolerant; errorCode is the one that wasn't.

Fix: type it ErrorCode | int | None, defaulting to None. Mapping null to 0 would assert the device is fault-free, which is not what a null says — the cloud reported no code. Both known consumers (ha_nwp500's cloud_error_code sensor and its diagnostics) already treat a missing code as nothing to report, so no downstream change is needed beyond the version pin.

Two tests cover it: an explicit null, and an error block with no errorCode key at all. docs/openapi.yaml marks the field nullable to match.

Note for anyone running the suite locally: the checked-in venv/ is Python 3.13 and can no longer import the package (converters.py uses PEP 758 unparenthesized except, and the project targets 3.14). Full suite passes on 3.14 — 737 tests.

The cloud returns "error": {"errorCode": null} on some devices.
DeviceErrorSummary typed the field ErrorCode | int, and neither union
branch accepts None, so a null failed validation of the entire Device -
taking the whole /device/list response with it. Downstream that meant the
device disappeared and the Home Assistant integration could not set up at
all (eman/ha_nwp500#131); the block was unmodelled before 9.3.1, which is
why rolling back restored service.

Type it ErrorCode | int | None, defaulting to None. Mapping null to 0
would assert the device is fault-free, which is not what a null says: the
cloud reported no code. Both known consumers already treat a missing code
as nothing to report.

Fixes #130

Claude-Session: https://claude.ai/code/session_01LhLMPrLpPJ56jUcQmiBh1d

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The OpenAPI 3.1 nullability syntax and public Python model documentation need correction.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Allows REST devices with null or missing errorCode values to remain parseable.

Changes:

  • Makes DeviceErrorSummary.error_code nullable.
  • Adds null and absent-field tests.
  • Updates changelog and OpenAPI documentation.
File summaries
File Description
src/nwp500/models/device.py Adds nullable error-code handling.
tests/test_device_rest_models.py Tests null and missing codes.
docs/openapi.yaml Documents nullability.
CHANGELOG.rst Records the fix.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +60 to +61
error_code: ErrorCode | int | None = Field(
default=None, union_mode="left_to_right"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 95e2232 — the field list now reads ErrorCode | int | None and explains that a null is "the cloud reported no code", not NO_ERROR. The example was worse than stale: error_code != ErrorCode.NO_ERROR is true for None, so it would have printed code None as a fault. It now pulls the code out first and guards on code is not None.

Comment thread docs/openapi.yaml Outdated
Comment on lines +222 to +224
errorCode:
type: integer
nullable: true

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Correct, and it applied to more than this line — nullable was used 15 times in the file, all predating this PR, so every one of them was being ignored by 3.1 tooling. Fixing only errorCode would have left it inconsistent with errorOccuredTime two lines below it, so 95e2232 converts all 15 to JSON Schema type arrays (type: [integer, "null"]). The file still parses as valid YAML and declares 3.1.0.

Two follow-ups from review:

OpenAPI 3.1 dropped `nullable` as a schema keyword, so 3.1 tooling read
`errorCode` as integer-only and the annotation did nothing. Express it as
a JSON Schema type array instead. The file had 15 of these, all predating
this change; converting only the new one would have left the same block
inconsistent with itself, so all 15 are converted.

`docs/reference/python_api/models.rst` still documented the field as
`ErrorCode | int`, and its example tested `error_code != NO_ERROR`, which
is true for None - it would have reported "code None" as a fault. Both
now describe the nullable contract.

Claude-Session: https://claude.ai/code/session_01LhLMPrLpPJ56jUcQmiBh1d
@eman
eman merged commit af9c1db into main Sep 1, 2026
7 checks passed
@eman
eman deleted the fix/null-error-code branch September 1, 2026 05:25
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.

Null errorCode in /device/list fails Device validation and loses the device

2 participants