Skip to content

fix(dexcomshare): surface auth failures, handle modern response shape, harden catch paths - #55

Open
csinghaus-sfdc wants to merge 1 commit into
nightscout:mainfrom
csinghaus-sfdc:fix/dexcomshare-error-handling-and-g7-response-shape
Open

fix(dexcomshare): surface auth failures, handle modern response shape, harden catch paths#55
csinghaus-sfdc wants to merge 1 commit into
nightscout:mainfrom
csinghaus-sfdc:fix/dexcomshare-error-handling-and-g7-response-shape

Conversation

@csinghaus-sfdc

Copy link
Copy Markdown

Summary

Fixes five related bugs in lib/sources/dexcomshare.js that together cause Dexcom Share authentication failures to never surface, produce misleading downstream 500s, and crash the catch paths on any non-HTTP error.

Field symptom (especially common for G7 accounts): the plugin reports RUNNING 0 failures 0 indefinitely and never stores new entries, even though logs claim type: 'AUTHENTICATED'. The actual underlying error from Dexcom is being swallowed.

Bugs fixed

  1. authFromCredentials returns the error object as a resolved value. The state machine treats it as a successful authentication and passes the Error object into sessionFromAuth as accountId. Dexcom then responds with 500 InvalidArgument: cannot deserialize java.util.UUID from Object value, hiding the real upstream cause (typically AccountPasswordInvalid). Fixed by re-rejecting the promise so the state machine runs its AUTHENTICATION_ERROR path.
  2. Modern Authenticate response shape not handled. Newer Dexcom accounts (observed on G7) get back {accountId: "<uuid>"} from AuthenticatePublisherAccount rather than a bare UUID string. The plugin sent the wrapper object as the next request's accountId. Fixed by normalizing to the bare UUID in authFromCredentials and accepting either shape defensively in sessionFromAuth.
  3. error.response.data typo in two catch blocks (sessionFromAuth, dataFromSesssion). The variable in scope is err. Catch block crashes with ReferenceError whenever entered. Fixed by using the right identifier.
  4. err.response dereferenced without an existence check. Crashes the catch path with TypeError on any non-HTTP error (DNS, ECONNRESET, TLS, timeout). Fixed with defensive access.
  5. transformGlucose does data.map() on whatever it receives, including non-array failure objects (especially with bug experimental capture mode #1 papering over auth failures). Fixed by guarding with Array.isArray.

The new error-log format also surfaces the Dexcom response body + the AxiosError message on a single line, which made diagnosing this PR's root cause take minutes instead of hours.

Testing

Validated against a live Dexcom G7 patient account on Heroku. Before the patch, the plugin looped silently with stale data and confusing logs. After the patch, the plugin surfaces AccountPasswordInvalid directly from Dexcom's response — a real auth issue the user can act on.

Notes

  • No new dependencies, no API changes, no test breakage expected.
  • The error-shape change in dataFromSesssion's catch (now Promise.reject instead of a wrapped object) is consistent with the other two paths and aligns with what the state machine seems to expect (it already handles rejection via its onError transitions).

Closes any open issue tracking the "0 entries forever" behavior or the cryptic UUID-deserialization 500s.

…, harden catch paths

Five related bugs in lib/sources/dexcomshare.js conspired to mask Dexcom
Share authentication failures and break G7-era accounts. Symptoms in the
field: silent "0 entries" polling for valid credentials, misleading
"InvalidArgument: cannot deserialize java.util.UUID from Object value"
500 responses from Dexcom for valid-but-misframed login flows, and
unhandled ReferenceError / TypeError crashes on any non-HTTP error path.

1. authFromCredentials swallowed errors by returning the AxiosError as a
   resolved value. The state machine treated that as a successful auth,
   then passed the Error object downstream where sessionFromAuth
   serialized it into the request body. Dexcom rejected that with the
   confusing UUID-deserialization 500, hiding the real upstream failure
   (e.g., AccountPasswordInvalid).
   Fix: re-reject so the state machine's AUTHENTICATION_ERROR path runs.

2. Dexcom's AuthenticatePublisherAccount endpoint now returns a JSON
   object containing accountId for newer (G7-era) accounts instead of a
   bare UUID string. The plugin assumed the bare-string shape and sent
   the wrapper object as accountId on the next request.
   Fix: in authFromCredentials normalize to the bare UUID; in
   sessionFromAuth accept either shape defensively.

3. catch blocks in sessionFromAuth and dataFromSesssion referenced
   `error.response.data` where the variable in scope is `err`. Any time
   the catch block was actually entered it would throw ReferenceError
   instead of returning the structured failure object.
   Fix: use the right identifier.

4. err.response was dereferenced without an existence check, so the
   catch path itself crashed with TypeError on any non-HTTP error (DNS
   failure, ECONNRESET, TLS handshake fail, request timeout).
   Fix: defensive optional access.

5. transformGlucose called data.map() on whatever it received, which
   could be a non-array failure object (especially given the
   error-swallowing in bug 1). TypeError instead of an empty-entries
   return.
   Fix: guard with Array.isArray.

The new catch-block log lines are also more useful for diagnostics:
they print status + body + the AxiosError's `message` field together
on a single line.

Validated against a live Dexcom G7 patient account on Heroku; the
patched plugin correctly surfaces AccountPasswordInvalid where
upstream silently looped on broken state.
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.

1 participant