Skip to content

ArcpOtel.injectTraceContext can throw ClassCastException when payload.extensions exists as a non-object node #51

@nficano

Description

@nficano

In arcp-otel/src/main/java/dev/arcp/otel/ArcpOtel.java the injectTraceContext method around line 172 reads ObjectNode ext = (ObjectNode) payload.path("extensions"); on line 179. If the payload has an "extensions" key whose value is not a JSON object — for example a string, array, or null — the cast throws ClassCastException at runtime, taking down the send call (which the TracingTransport wraps with a try/finally that records the exception and rethrows). Any envelope shape that legitimately uses "extensions" as something other than an object (the spec does not mandate object semantics for the field) will break tracing.\n\nThe block of code immediately following the cast is also dead. After if (ext.isMissingNode()) { ext = payload.putObject("extensions"); } runs and creates a fresh object, the subsequent else if (!payload.has("extensions")) can never be true (the path() call against a missing node still leaves payload unchanged but the subsequent has() check is now meaningfully wrong, and even when ext is not missing the else-if branch is unreachable because if path() returned a real node, payload.has("extensions") is by definition true).\n\nThe extractTraceContext method directly below has the same unguarded cast risk on line 201.\n\nFix prompt: In arcp-otel/src/main/java/dev/arcp/otel/ArcpOtel.java rewrite both injectTraceContext and extractTraceContext to type-check payload.path("extensions") against JsonNode.isObject() before casting. If the value exists but is not an object, log a warning at WARN level and return the envelope unchanged (for inject) or Context.current() (for extract) without throwing. Delete the dead else if (!payload.has("extensions")) branch — the only meaningful path is "missing → create new object" or "already an object → reuse." Add JUnit tests in arcp-otel/src/test/java/dev/arcp/otel/ that exercise three cases: extensions absent, extensions present as an object, and extensions present as a string or array. The third must round-trip cleanly without throwing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingseverity:mediumMedium severity

    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