Skip to content

fix(cluster): build a NodeInfo before calling NodeRegistry.register in RegisterNode - #3524

Open
AmirF194 wants to merge 1 commit into
sipyourdrink-ltd:mainfrom
AmirF194:fix/3500-registernode-kwargs-mismatch
Open

fix(cluster): build a NodeInfo before calling NodeRegistry.register in RegisterNode#3524
AmirF194 wants to merge 1 commit into
sipyourdrink-ltd:mainfrom
AmirF194:fix/3500-registernode-kwargs-mismatch

Conversation

@AmirF194

@AmirF194 AmirF194 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What

ClusterServiceImpl.RegisterNode (the gRPC entry point for bernstein.v1.ClusterService/RegisterNode) raised TypeError on every call.

Why

NodeRegistry.register(node: NodeInfo) -> NodeInfo takes a single positional NodeInfo. The gRPC handler instead called it with NodeInfo's own constructor keywords:

node = self._registry.register(
    name=request.name,
    url=request.url,
    capacity=cap,
    labels=dict(request.labels) if request.labels else {},
    cell_ids=list(request.cell_ids) if request.cell_ids else [],
)

TypeError: NodeRegistry.register() got an unexpected keyword argument 'name', unconditionally, for any node trying to join a cluster over gRPC. The two other call sites in the codebase (POST /cluster/nodes in task_cluster.py, and ClusterAuthGate.register_node in cluster_auth.py) already build a NodeInfo first and pass it positionally; RegisterNode was the one call site that skipped that step.

How

Build the NodeInfo from the request fields, then pass it positionally, matching the two working call sites.

Fixes #3500

Verification

  • New regression test (TestClusterServiceImplRegisterNode::test_register_node_stores_a_real_node) fails on unmodified main with the exact TypeError above, and passes on this branch, asserting the registered node's name, url, capacity fields, labels and cell_ids.
  • uv run python scripts/run_tests.py -k grpc (13 tests) and -k cluster (13 files, 172 tests) pass. Did not run the full suite.
  • ruff check src/, ruff format --check, and lint-imports pass; pyright on the changed file goes from 183 to 179 pre-existing errors (this file sits outside pyrightconfig.strict.json's scope; the drop is the removed invalid-kwargs call).
  • Not verified: the gRPC wire path end to end (no cluster_pb2 stubs generated in this environment). The test calls ClusterServiceImpl.RegisterNode directly with a fake request and a mocked cluster_pb2 module.

Checklist

  • uv run ruff check src/ passes
  • uv run pyright src/ passes (pre-existing repo-wide backlog outside pyrightconfig.strict.json, unrelated to this change)
  • uv run python scripts/run_tests.py -x passes (ran only -k grpc and -k cluster, see Verification)
  • New code has type hints

Documentation duty (every PR that touches a feature)

  • User-visible README section updated (or N/A if internal-only) - N/A, no user-facing behavior beyond the bug fix, noted in the changelog
  • docs/operations/<area>.md updated (or N/A) - N/A
  • docs/api/ schema regenerated if a public surface changed (or N/A) - N/A, no proto/schema change
  • uv run bernstein agents-md sync run so AGENTS.md, CLAUDE.md, .goosehints, CONVENTIONS.md, and .cursor/rules/*.mdc reflect any new module (or N/A) - N/A, no new module
  • Tests cover the documented behaviour

…n RegisterNode

ClusterServiceImpl.RegisterNode called NodeRegistry.register() with
NodeInfo's own constructor keywords (name=, url=, capacity=, labels=,
cell_ids=), but register() takes one positional NodeInfo. Every gRPC
node registration raised TypeError. Build the NodeInfo first, matching
the pattern POST /cluster/nodes and ClusterAuthGate.register_node
already use.

Fixes sipyourdrink-ltd#3500
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gRPC RegisterNode calls NodeRegistry.register with NodeInfo's constructor arguments

1 participant