Hi zrok team,
I’m reporting a recurring problem with named public shares after restarting the zrok2 agent. The agent starts, but a public share can remain in retrying because the previous share still holds its reserved name on the controller. Every retry then fails with 409 shareConflict, and the public URL stays unavailable.
Here is a step-by-step example of the failure:
- Start a local HTTP service at
http://127.0.0.1:8080.
- Reserve a name:
zrok2 create name restart-repro.
- Start
zrok2 agent start under a process supervisor.
- Register the share:
zrok2 share public http://127.0.0.1:8080 --name-selection public:restart-repro --open --headless --force-agent.
- Confirm that the URL works and
zrok2 agent status shows the share as active.
- Restart the agent. The failure occurs when shutdown does not finish cleanly, including a supervisor timeout or an abrupt host shutdown.
- After the agent starts again,
zrok2 agent status shows the share as retrying, while zrok2 list shares still shows the previous share holding the name. The agent repeatedly receives: 409 shareConflict: name 'restart-repro' in namespace 'public' is already in use by another share.
Expected: The agent restores the public URL automatically, either by reattaching to the existing share or safely reconciling the stale controller record.
Actual: Retries cannot resolve the conflict. Recovery requires manually deleting the previous share and letting the agent create another one. Deleting and recreating every public share after an agent restart is unacceptable for endpoints that are expected to remain available.
My current setup is macOS, zrok2 v2.0.8, with the agent managed by PM2. I have experienced this 409 during restarts, but have not intentionally repeated the restart on the current build because it would interrupt active public shares. The behavior also matches GitHub issue #1259 and this Discourse report.
Is reliable reattachment of named public shares supported today? If not, is there a fix planned? Please also provide a supported recovery procedure that does not require deleting every share in the account on each startup.
I would bet your process supervisor isn't sending SIGTERM or SIGINT to the agent at shutdown time. If it's sending SIGKILL, you're circumventing the normal shutdown process of the agent, which leads to the issue you're seeing.
If you effectively "pull the plug" on the agent (and not giving it a change to clean up properly), you're going to have to manually clean up the attached (but dead) shares. If you send SIGTERM or SIGINT, these will get shut down properly and your agent will restart cleanly.
And you can use zrok2 overview to see the contents of your account, and zrok2 delete share to delete any dead shares attached to names. You for sure do not need to "delete every share in the account on each startup".
Thanks for looking into this. I checked the actual restart records. PM2 runs /opt/homebrew/bin/zrok2 agent start in fork mode, and on October 15 at 17:46:48 and 18:03:17 its log says it sent SIGINT to zrok2-agent. On both occasions the agent then logged stopping and preserving reserved share ... on controller for reattach within milliseconds. The newly started agent encountered 409 shareConflict less than a second later. So these failures occurred after the agent received the graceful signal and preserved the named share itself.
PM2 has no explicit kill_timeout configured, so its default 1.6-second deadline is worth increasing as a separate safeguard. But the preservation step had already completed before the conflict in these recorded restarts. I have not restarted the currently active shares just to reproduce the outage.
Looking at v2.0.8, the agent preserves a reserved share during shutdown, but registry reload calls SharePublic again. The public share path appears to create a new share, while the controller rejects a name still held by the previous share. Is there a reattachment path for a named public share that I am missing, or is this a gap in v2.0.8?
You are right about cleanup: zrok2 overview and zrok2 delete share public:<name> let us target only the dead share. My wording about deleting every share in the account was inaccurate. The remaining problem is the manual cleanup required for an affected named share after a normal restart.
This sounds suspect to me... in the zrok.io environment, I would surprised if the full cleanup were done in less than a second. It's possible, but it's unlikely.
In normal use, there's the agent process itself (zrok2 agent start)... and then there are the zrok2 share <public|private> --subordinate and the zrok2 access private --subordinate processes, which actually service the shares and accesses. It's possible there's something going wrong either on macOS, or on macOS under PM2... the agent process records the registry/state, but it's the share/access processes that do the actual cleanup with the service. If that's not happening properly for any reason, then you'll end up in the situation you describe.
Have you tried running zrok2 agent start in a plain terminal, and doing a normal ctrl-c exit, and watching what happens? Does that work properly on your system? If so, then there's a delta between that and what PM2 is doing when managing these processes.
Alternatively, you could also just let PM2 manage individual zrok2 share processes, rather than inserting the zrok agent... the zrok agent is a process manager also, and two layers of process management might be causing issues.
Not saying there aren't bugs in the agent... or cases that haven't been considered... there probably are... but working with the grain might get you solid more quickly.