`ax exec --resume` on pending execution fails with 'no input messages queued'
- Dominant language
- Go
- Stars
- 2k
- Forks
- 120
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`ax exec --resume` against a conversation that's in `STATE_PENDING`
(e.g., the harness died mid-stream on a previous turn) fails
with:
```
harness execution failed: no input messages queued for execution turn
```
The gRPC `HarnessService.Connect` stream is not opened.
## Reproduction (verified end-to-end against a local Antigravity
harness server talking to Vertex / Gemini 2.5 Flash)
Force a PENDING execution by killing the harness mid-stream:
```
$ ax exec --conversation t5 --input "Count from 1 to 30 slowly, ..." &
(after ~4s, while streaming)
$ systemctl --user kill -s KILL axharness
→ ax exits with: gRPC harness streaming failure: rpc error: code = Unavailable
→ event log: 2 events, both STATE_PENDING
```
Bring the harness back and try to resume:
```
$ systemctl --user start axharness
$ ax exec --conversation t5 --resume
→ harness execution failed: no input messages queued for execution turn
```
## Root cause
[`Controller.Exec`](https://github.com/google/ax/blob/cdc7688/internal/controller/controller.go#L90-L103)
that calls `h.Start(...)` followed directly by `exec.Run(...)` with
**no intervening `exec.Queue(...)`**:
```go
if state == proto.State_STATE_PENDING {
exec, err := h.Start(ctx, req.ConversationId)
if err != nil { ... }
defer exec.Close(ctx)
if err := exec.Run(ctx, hhandler); err != nil { // 👈 no Queue
return fmt.Errorf("harness execution failed: %w", err)
}
}
```
But [`AntigravityHarness.Run`](https://github.com/google/ax/blob/cdc7688/internal/harness/antigravity.go#L99-L101)
rejects an empty queue:
```go
if len(inputs) == 0 {
return fmt.Errorf("no input messages queued for execution turn")
}
```
That's the source of the error string above — it comes from the Go
client (`internal/harness/antigravity.go:100`), not from the python
harness server. The request never leaves the Go process.
Note: [`SubstrateHarness.Run`](https://github.com/google/ax/blob/cdc7688/internal/harness/substrate.go)
does not have this guard, which is a separate inconsistency (cf. #181
side observation).
## Why removing the guard isn't sufficient
If the guard is removed, the request reaches the python harness
server, which then hits its own equivalent rejection in
[`harness_server.py:172-178`](https://github.com/google/ax/blob/cdc7688/python/antigravity/harness_server.py#L172-L178):
```python
if not ax_messages:
yield ax_pb2.HarnessResponse(
end=ax_pb2.HarnessEnd(state=STATE_FAILED,
error_message="No messages found in start payload"))
return
```
So the "empty `HarnessStart.Messages` means resume" heuristic
currently conflicts at two layers (Go client + python server). The
wire protocol has no explicit way to express "resume intent vs new
turn with no input".
Contributor guide
Assessment
This issue has not been assessed yet.