{"record":{"id":"5b85ff8b84100227","repo":"netbirdio/netbird","slug":"expose-service-v","errorCode":null,"errorMessage":"expose service: %v","messagePattern":"expose service: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/expose.go","lineNumber":205,"sourceCode":"\t\treturn err\n\t}\n\n\treq := &proto.ExposeServiceRequest{\n\t\tPort:       uint32(port),\n\t\tProtocol:   protocol,\n\t\tPin:        exposePin,\n\t\tPassword:   exposePassword,\n\t\tUserGroups: exposeUserGroups,\n\t\tDomain:     exposeDomain,\n\t\tNamePrefix: exposeNamePrefix,\n\t}\n\tif isClusterProtocol(exposeProtocol) {\n\t\treq.ListenPort = uint32(resolveExternalPort(port))\n\t}\n\n\tstream, err := client.ExposeService(ctx, req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"expose service: %v\", status.Convert(err).Message())\n\t}\n\n\tif err := handleExposeReady(cmd, stream, port); err != nil {\n\t\treturn err\n\t}\n\n\treturn waitForExposeEvents(cmd, ctx, stream)\n}\n\nfunc toExposeProtocol(exposeProtocol string) (proto.ExposeProtocol, error) {\n\tp, err := expose.ParseProtocolType(exposeProtocol)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"invalid protocol: %w\", err)\n\t}\n\n\tswitch p {\n\tcase expose.ProtocolHTTP:\n\t\treturn proto.ExposeProtocol_EXPOSE_HTTP, nil","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/expose.go#L187-L223","documentation":"The initial client.ExposeService RPC was rejected by the daemon; the gRPC status message is surfaced. By this point every flag passed validateExposeFlags, the daemon connection was live, and the request (port, protocol enum, pin/password/user-groups, domain, name prefix, and ListenPort for L4) had been sent — so the failure is a daemon-side or management-side refusal, not a CLI validation issue.","triggerScenarios":"The peer is not connected or not logged in, so the daemon refuses to create an exposed service; the management plane does not support the services feature; a --with-custom-domain value that is not configured on the account; server-side validation rejecting name prefix or domain; the expose subsystem on the daemon not being ready; the context canceled before the RPC was sent.","commonSituations":"Running `netbird expose` before `netbird up` has finished connecting; self-hosted management older than the services feature; assuming any domain string works with --with-custom-domain; running against a management account where the reverse-proxy feature is disabled.","solutions":["Make sure the peer is connected first: `netbird status` must show Connected; run `netbird up` and wait, then retry","Confirm your management/account supports exposed services (cloud feature flag or self-hosted management version) and that it is enabled for the account","If using --with-custom-domain, verify the domain is added and verified for your account in the dashboard, or drop the flag to get an assigned domain","Re-run with the daemon at debug log level and read its log at the failure timestamp for the exact refusal reason"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# require a healthy, connected peer before exposing\nnetbird status --check live || { echo 'peer not connected; run netbird up first'; exit 1; }","typeGuard":null,"tryCatchPattern":"stream, err := client.ExposeService(ctx, req)\nif err != nil {\n\tmsg := status.Convert(err).Message()\n\tswitch status.Code(err) {\n\tcase codes.FailedPrecondition:\n\t\t// peer not connected/logged in: bring it up, then retry\n\t\treturn fmt.Errorf(\"expose service: connect the peer first (netbird up): %s\", msg)\n\tcase codes.InvalidArgument:\n\t\t// server-side validation (domain, name prefix): fix the flags\n\t\treturn fmt.Errorf(\"expose service: invalid request (%s); check --with-custom-domain/--with-name-prefix\", msg)\n\tdefault:\n\t\treturn fmt.Errorf(\"expose service: %s\", msg)\n\t}\n}","preventionTips":["Run `netbird up` and confirm Connected in `netbird status` before exposing anything","Verify the management account supports services/expose before scripting around it","Only pass --with-custom-domain with a domain already configured and verified in the dashboard","Capture the daemon log when the status message is vague — the daemon logs the refusal reason"],"tags":["grpc","daemon","expose","management","netbird-cli"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}