chenhg5/cc-connect · error

turn failed (no details)

Error message

turn failed (no details)

What it means

Raised by the codex app-server session when a `turn/completed` notification arrives with status "failed" (or an error object) but the error payload carries no usable message text. The adapter cannot report a cause, so it substitutes the placeholder "turn failed (no details)" and fails the pending turn via failTurn. It means the codex app-server aborted the turn without explaining why.

Source

Thrown at agent/codex/appserver_session.go:1137

	case "item/completed":
		var notif itemNotification
		if err := json.Unmarshal(paramsRaw, &notif); err == nil {
			s.handleItemCompleted(notif.Item)
		}

	case "turn/completed":
		var notif turnNotification
		if err := json.Unmarshal(paramsRaw, &notif); err == nil {
			if strings.EqualFold(strings.TrimSpace(notif.Turn.Status), "failed") || notif.Turn.Error != nil {
				errMsg := ""
				if notif.Turn.Error != nil {
					errMsg = strings.TrimSpace(notif.Turn.Error.Message)
				}
				if errMsg == "" {
					errMsg = "turn failed (no details)"
				}
				s.failTurn(fmt.Errorf("%s", errMsg))
			} else {
				s.completeTurn()
			}
		}

	case "thread/status/changed":
		var notif struct {
			ThreadID string `json:"threadId"`
			Status   struct {
				Type string `json:"type"`
			} `json:"status"`
		}
		if err := json.Unmarshal(paramsRaw, &notif); err == nil && notif.Status.Type == "idle" {
			// In codex 0.125+, thread going idle signals turn completion.
			s.completeTurn()
		}

	case "account/rateLimits/updated":

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Run the codex CLI directly on the same prompt to see the underlying failure (auth expired, model unavailable, quota exhausted).
  2. Check codex CLI version and upgrade both the codex binary and cc-connect so the error schema matches (`codex --version`).
  3. Verify codex authentication (`codex login`) and API quota; silent failures often mean expired credentials.
  4. Inspect the codex app-server's own logs/stderr for the real error text that was not carried in the notification.
  5. Retry the turn; transient backend failures often surface as bare failed status.

Example fix

// before: error text missing, no way to see why
errMsg := "turn failed (no details)"

// after: log the raw notification for debugging
if notif.Turn.Error != nil {
    errMsg = strings.TrimSpace(notif.Turn.Error.Message)
}
if errMsg == "" {
    slog.Warn("codex turn failed without error details", "status", notif.Turn.Status)
    errMsg = "turn failed (no details)"
}
Defensive patterns

Strategy: try-catch

Try / catch

// consume session events
for ev := range sess.Events() {
    if ev.Type == core.EventError {
        if strings.Contains(ev.Error.Error(), "no details") {
            slog.Warn("codex turn failed without cause; check codex CLI logs")
        }
        // surface to user or retry
    }
}

Prevention

When it happens

Trigger: The `turn/completed` JSON-RPC notification is received where `notif.Turn.Status` equals "failed" (case-insensitive) or `notif.Turn.Error` is non-nil, AND `notif.Turn.Error.Message` is empty or whitespace-only.

Common situations: Codex app-server crashes or hits an internal error mid-turn without populating the error message; protocol version drift (codex 0.125+) where the error schema changed and the message field moved or was renamed; overloaded backend returning bare failure status; malformed turn error payloads after proxying.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/fe516e8c16e2aa0c. Report an issue: GitHub.