{"record":{"id":"c65ff2a66e85a5e3","repo":"netbirdio/netbird","slug":"expose-w","errorCode":null,"errorMessage":"expose: %w","messagePattern":"expose: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/embed/embed.go","lineNumber":438,"sourceCode":"\t}\n}\n\n// Expose exposes a local service via the NetBird reverse proxy, making it accessible through a public URL.\n// It returns an ExposeSession. Call Wait on the session to keep it alive.\nfunc (c *Client) Expose(ctx context.Context, req ExposeRequest) (*ExposeSession, error) {\n\tengine, err := c.getEngine()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmgr := engine.GetExposeManager()\n\tif mgr == nil {\n\t\treturn nil, fmt.Errorf(\"expose manager not available\")\n\t}\n\n\tresp, err := mgr.Expose(ctx, req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"expose: %w\", err)\n\t}\n\n\treturn &ExposeSession{\n\t\tDomain:      resp.Domain,\n\t\tServiceName: resp.ServiceName,\n\t\tServiceURL:  resp.ServiceURL,\n\t\tmgr:         mgr,\n\t}, nil\n}\n\n// IdentityForIP looks up a remote peer by its tunnel IP using the\n// embedded client's status recorder. Returns the peer's WireGuard public\n// key and FQDN. ok=false means the IP doesn't belong to an active peer\n// — offline roster peers are treated as unknown, same as foreign IPs.\nfunc (c *Client) IdentityForIP(ip netip.Addr) (pubKey, fqdn string, ok bool) {\n\tif !ip.IsValid() || c.recorder == nil {\n\t\treturn \"\", \"\", false\n\t}","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/embed/embed.go#L420-L456","documentation":"Returned by Client.Expose when the expose manager's Expose call fails. This is the management-driven reverse proxy feature: the manager talks to the management server to register the exposed service and obtain a public URL, so failures are registration/protocol/network level: management rejected the request, feature unavailable for the account, connectivity loss, or context cancellation.","triggerScenarios":"Expose with a context that is cancelled/deadline exceeded; management server unreachable or returning an error for the expose request; expose feature not enabled on the NetBird account/plan; malformed ExposeRequest fields (e.g. invalid port or name) rejected server-side.","commonSituations":"Trying expose on a self-hosted management without the reverse proxy feature configured; expired auth session between the client and management; network partitions between the embedder and management at expose time.","solutions":["Unwrap the error to distinguish transport failures (retry) from management rejections (fix request/plan).","Ensure the ExposeRequest values (ports, names) are valid and the management server supports the expose feature.","Retry with backoff on transient connectivity loss; use a context without an aggressive deadline.","Verify the client is still connected (Status) before exposing."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"sess, err := client.Expose(ctx, req)\nif err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || isTransientNet(err) {\n        // backoff and retry with a fresh context\n    } else {\n        // management rejected: fix request or account feature, do not retry\n    }\n}","preventionTips":["Confirm the management server/account has the reverse proxy (expose) feature before building on it.","Use a context with a realistic deadline and retry transient failures with backoff."],"tags":["expose","proxy","network","embed"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}