Skip to content

Guard against null metadata node in ShadowStateMetadata.buildMetadata (fixes NPE) - #223

Open
Atsushi570 wants to merge 2 commits into
aws-greengrass:mainfrom
Atsushi570:fix/buildmetadata-npe-null-guard
Open

Guard against null metadata node in ShadowStateMetadata.buildMetadata (fixes NPE)#223
Atsushi570 wants to merge 2 commits into
aws-greengrass:mainfrom
Atsushi570:fix/buildmetadata-npe-null-guard

Conversation

@Atsushi570

Copy link
Copy Markdown

Issue

Fixes the NullPointerException reported in #222.

Problem

ShadowStateMetadata.getDeltaMetadata(delta) calls buildMetadata(delta, desired). buildMetadata recurses the delta tree and dereferences the corresponding metadata node without a null guard:

// array branch
final ArrayNode metadataArray = (ArrayNode) metadataNode;   // metadataNode may be null
... metadataArray.get(i)                                    // -> NullPointerException

// object branch
final ObjectNode metadataObjectNode = (ObjectNode) metadataNode;   // metadataNode may be null
... metadataObjectNode.get(fieldName)                              // -> NullPointerException

When a delta node exists at a path where the desired metadata subtree is null/missing (a state vs. metadata structural inconsistency), metadataNode is null and the array/object handling throws NPE.

Observed on a production Greengrass device (Nucleus 2.16.1 / ShadowManager 2.3.12): a local pub/sub shadow update fails with:

java.lang.NullPointerException
    at com.aws.greengrass.shadowmanager.model.ShadowStateMetadata.buildMetadata(ShadowStateMetadata.java:294)
    at com.aws.greengrass.shadowmanager.model.ShadowStateMetadata.getDeltaMetadata(ShadowStateMetadata.java:254)
    at com.aws.greengrass.shadowmanager.model.ShadowDocument.getDelta(ShadowDocument.java:202)
    at com.aws.greengrass.shadowmanager.ipc.UpdateThingShadowRequestHandler.publishDeltaMessage(UpdateThingShadowRequestHandler.java:309)
    at com.aws.greengrass.shadowmanager.ipc.UpdateThingShadowRequestHandler.handleRequest(UpdateThingShadowRequestHandler.java:94)
    at com.aws.greengrass.shadowmanager.PubSubIntegrator.handlePublishedMessage(PubSubIntegrator.java:121)
    ...

The exception is unhandled at the IPC layer, so the update is dropped (PubSubIntegrator: Unable to perform shadow operation), the delta is never published, and every subsequent update to the affected shadow repeats the NPE.

Fix

Add an isNullOrMissing(metadataNode) guard in buildMetadata right after the value-node check. If there is no metadata for a delta subtree, the subtree is skipped (returns null) instead of dereferencing null in the array/object handling. This also naturally covers the array-index case where the metadata array is shorter than the delta array (ArrayNode.get(i) returns null for an out-of-range index, which now recurses into the guarded branch).

Test

Added GIVEN_delta_field_missing_from_metadata_WHEN_getDeltaMetadata_THEN_does_not_throw: a delta with an array field whose desired metadata has no corresponding node. Before the fix this threw NPE; after the fix getDeltaMetadata completes, keeps fields that do have metadata, and treats the field with missing metadata as null/missing.

Notes

  • I was unable to run the Maven build/tests locally (no Maven/toolchain in my environment), so the change is verified by code inspection and follows the existing test style. Please run CI.
  • I have not been able to capture a minimal reproduction of the exact document that produces the state/metadata mismatch in the field (the shadow reconciles too quickly to capture the offending state live), but the missing null guard is evident from the source and the stack trace above is from a production device.

…adata

buildMetadata dereferenced the metadata node without a null check when the delta
node was an array or object. When the delta and the desired metadata are
structurally inconsistent (a delta node exists at a path where the desired
metadata is null/missing), this threw a NullPointerException, aborting the shadow
update and preventing the delta from being published. In steady state this
repeats on every subsequent update to the affected shadow.

Add an isNullOrMissing(metadataNode) guard so the subtree is skipped gracefully,
plus a regression test.

See aws-greengrass#222

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants