Skip to content

fix: normalize bare hosted NAMS endpoint to /v1 (#129) - #166

Open
Navaneethp007 wants to merge 1 commit into
neo4j-labs:mainfrom
Navaneethp007:fix/129-nams-endpoint-v1-detection
Open

fix: normalize bare hosted NAMS endpoint to /v1 (#129)#166
Navaneethp007 wants to merge 1 commit into
neo4j-labs:mainfrom
Navaneethp007:fix/129-nams-endpoint-v1-detection

Conversation

@Navaneethp007

Copy link
Copy Markdown

Summary

A bare hosted endpoint silently spoke the wrong wire protocol. NamsConfig(endpoint="https://memory.neo4jlabs.com") — the base URL as printed in the docs, without the /v1 suffix — fails the /v<N> search in detect_protocol, which falls back to the TCK bridge protocol. The SDK then sent snake-case bridge POSTs to the REST-only hosted service and failed with no indication that the endpoint was the cause. Now normalized to https://memory.neo4jlabs.com/v1 when the endpoint targets the hosted host and carries no version segment.

Normalizing the endpoint, not detect_protocol

The obvious fix — make detect_protocol return "rest" for the hosted host — is insufficient. build_url constructs REST URLs as base + rest_path, so the request would still go to https://memory.neo4jlabs.com/conversations/… with no /v1: right protocol, wrong path. The version segment has to live in the endpoint string itself, which fixes both the detection and the URL in one move.

Scoped to the hosted host

A blanket "append /v1 when missing" would break the TCK bridge. test_localhost_no_version_is_bridge asserts that http://localhost:8000 resolves to bridge, and that's deliberate — the bridge protocol is what the conformance reference implementation speaks. Normalization therefore keys on the hostname; version-less on-prem and localhost endpoints are untouched.

The MEMORY_ENDPOINT env alias was a second vector

_resolve_backend sets the endpoint by direct assignment (self.nams.endpoint = env_endpoint), and Pydantic v2 does not run field validators on assignment unless validate_assignment=True. A NamsConfig validator alone would have left this path broken, so the normalization is factored into a module-level helper applied at both entry points.

Deferred to a follow-up

This is a targeted fix and does not address the underlying design:

  • It fixes one host, not the bug class. Any REST-only deployment reached at a version-less URL still falls back to bridge silently.
  • The hostname is hardcoded. Regional hosts or a rename would make the normalization stop applying, with no test to catch it.
  • The fallback direction is arguably inverted. Bridge is the rare case, but it is the default for any unrecognized endpoint. REST-by-default with transport_mode="bridge" as the explicit opt-in would cover the whole class — but that is a breaking change and a maintainer call, not something to fold into a bug fix.
  • The real defect is that the mismatch is silent. Surfacing it as an error ("this looks like a REST service — did you mean /v1?") would generalize the fix; NamsConfig.validate_on_connect looks like the natural hook.

Happy to open a follow-up issue for any of these if the direction is welcome.

Verification

  • 8 new tests in tests/unit/nams/test_settings.py: normalization (bare, trailing slash), resulting REST detection, no-ops (/v1, /v2 already present), guards (localhost, other hosts), and the env alias path.
  • Full unit suite green: 1415 passed, 4 skipped.
  • ruff check + ruff format --check clean; mypy clean on the touched module.

Fixes #129.

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

@Navaneethp007 is attempting to deploy a commit to the lyonwj's projects Team on Vercel.

A member of the Team first needs to authorize it.

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.

[Python SDK] NamsConfig requires endpoint with /v1 suffix — quick-start docs use base URL without it

1 participant