iOfficeAI/OfficeCLI · error · InvalidOperationException
Another watch process is already running{url} for {_filePath
Error message
Another watch process is already running{url} for {_filePath} What it means
Thrown by WatchServer.RunAsync when a watch is already running for the same file (GetExistingWatchPort returns a port from the marker file). It prevents two watch processes racing on one file. The message includes the existing URL when the port is positive, so the user can reuse the running watch instead of starting a duplicate.
Source
Thrown at src/officecli/Core/Watch/WatchServer.cs:316
private void DeleteMarker()
{
try
{
var markerPath = GetWatchMarkerPath(_filePath);
if (File.Exists(markerPath)) File.Delete(markerPath);
}
catch { /* best-effort cleanup */ }
}
public async Task RunAsync(CancellationToken externalToken = default)
{
// Prevent duplicate watch processes for the same file
var existingPort = GetExistingWatchPort(_filePath);
if (existingPort.HasValue)
{
var url = existingPort.Value > 0 ? $" at http://localhost:{existingPort.Value}" : "";
throw new InvalidOperationException($"Another watch process is already running{url} for {_filePath}");
}
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_cts.Token, externalToken);
var token = linkedCts.Token;
_tcpListener.Start();
// --port 0 asks the OS for an ephemeral port; resolve the real one
// before it reaches the marker file and the printed URL, otherwise
// both would say 0 and per-file discovery (mark/goto/unwatch,
// IsWatching) breaks.
if (_port == 0)
_port = ((IPEndPoint)_tcpListener.LocalEndpoint!).Port;
WriteMarker();
Console.WriteLine($"Watch: http://localhost:{_port}");
Console.WriteLine($"Watching: {_filePath}");
Console.WriteLine("Press Ctrl+C to stop.");
// Hook graceful shutdown signals. Cooperatively terminating aView on GitHub (pinned to 1ced45e900)
Solutions
- Reuse the existing watch — open/connect to the URL printed in the message.
- Stop the running watch first (unwatch / SendClose / Ctrl+C), then start a new one.
- If the marker is stale (no real watch bound), remove the marker file and retry.
Example fix
# before: second `watch file.docx` while one runs # after: reuse the running watch # open the URL from the error, or stop it first: unwatch file.docx # then re-run watch
Defensive patterns
Strategy: validation
Validate before calling
// Check before starting a watch
int? port = WatchServer.GetExistingWatchPort(filePath);
if (port.HasValue)
Console.WriteLine($"already watching at http://localhost:{port.Value}"); Try / catch
try { await server.RunAsync(token); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already running"))
{ /* reuse the existing watch URL, or SendClose then retry */ } Prevention
- Always check GetExistingWatchPort/IsWatching before starting a watch.
- Clean up watch processes explicitly on exit to avoid stale markers.
When it happens
Trigger: Starting a second watch for a file that already has a live watch process; a previous watch left a stale marker file pointing at a still-bound port.
Common situations: Forgetting a watch is already running; a stuck/stale marker after an unclean shutdown; automation spawning parallel watches for the same file.
Related errors
- {error}
- Pipe communication timed out
- -1
- file_locked
- Cannot read OLE source file '{srcPath}': the file is locked
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/5e231d4bb4ca43ba.
Report an issue: GitHub.