Skip to content

Added null check to matcher result. - #174

Merged
stevehu merged 1 commit into
masterfrom
173-npe-occurs-when-a-call-path-matches-a-function-but-not-the-method
Jul 21, 2026
Merged

Added null check to matcher result.#174
stevehu merged 1 commit into
masterfrom
173-npe-occurs-when-a-call-path-matches-a-function-but-not-the-method

Conversation

@KalevGonvick

Copy link
Copy Markdown
Member

Added null check to prevent .match(...) call when match result is null.

@KalevGonvick
KalevGonvick requested a review from stevehu July 21, 2026 18:03
@KalevGonvick KalevGonvick linked an issue Jul 21, 2026 that may be closed by this pull request
@stevehu

stevehu commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Overview

Fixes #173: an NPE in LambdaProxyMiddleware.execute when a request path matches a configured function but the HTTP method has no entry in methodToMatcherMap. map.get(method) returned null and .match(path) was called on it unconditionally. The PR hoists the lookup into a local and guards it, letting the existing result == null branch handle the miss.

Two lines, correct, minimal, and it lands exactly on the reported defect.

Correctness

  • The fix is right. The null matcher now flows into the pre-existing result == null branch, which logs and returns FAILED_TO_INVOKE_LAMBDA with path + "@" + method. No new branch, no behavior change on the happy path.
  • The two null cases collapse cleanly. "No matcher for this method" and "matcher exists but path didn't match" both mean "no lambda for this path+method," and the error message includes both, so the collapse doesn't lose diagnostic information.
  • ERR10086 maps to HTTP 400 (light-4j status.yml:574), so the client gets a 4xx rather than a 500 from an uncaught NPE. That's the right outcome — this is a client-side routing miss, not a server fault.

The root cause this doesn't address

Worth raising on the issue even if it's out of scope for this PR. There's a case-normalization asymmetry:

  • execute looks up with exchange.getRequest().getHttpMethod().toLowerCase() (line 95)
  • populateMethodToMatcherMap keys the map with endpoint[1] verbatim (line 129), no lowercasing

So a config entry written /v1/pets@GET registers under key GET, and every request for it looks up get and misses. Before this PR that was an NPE; after it, it's a clean 400 — but the route still silently never works. Normalizing at line 129 (endpoint[1].toLowerCase()) would make those configs function rather than fail politely. I'd suggest it as a follow-up; the PR is still correct without it.

Other observations

  • getHttpMethod() can still NPE at line 95 if the method is absent from the request event. Same class of bug, one line up, untouched. Not a regression and arguably can't happen behind API Gateway — just noting it's adjacent.
  • populateMethodToMatcherMap has a redundant put (line 134): computeIfAbsent already inserts, and matcher is mutated in place, so the trailing put is a no-op. Also endpoint[1] will ArrayIndexOutOfBounds on a malformed config key with no @. Both pre-existing; mentioning only because the fix touches this code path.
  • Style is consistent with the file. The explicit PathTemplateMatcher declaration rather than var matches the existing explicit type on the result line directly below it. Ternary over an if keeps the diff to two lines.

Test coverage

This is the one substantive gap. MockLambdaProxyMiddlewareTest has a single testConstructor case that asserts the happy path (get + /v1/pets/123), and MockLambdaProxyMiddleware doesn't share the fixed code — it has its own execute using a direct CONFIG.getFunctions().get(...) lookup, so it can't exercise this path at all.

A regression test would need to hit the real LambdaProxyMiddleware. Even a narrow unit test asserting that an unmapped method yields Status ERR10086 instead of throwing would lock in the fix. Without one, nothing stops this from regressing.

Security & performance

  • No security surface change. The error message echoes path + "@" + method back into the Status — already the case before this PR, and consistent with the existing failure branch, so no new reflection of user input.
  • Performance is neutral-to-marginally-better: one map lookup instead of one lookup plus a method call, and the failure path now short-circuits before match().

Verdict

Approve. Correct, minimal, appropriately scoped to the reported NPE. Two follow-ups I'd open separately rather than block on: the toLowerCase() asymmetry in populateMethodToMatcherMap (which is likely the real reason users hit this), and a regression test against the real middleware.

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.

NPE Occurs When A Call Path Matches A Function But Not The Method

2 participants