chenhg5/cc-connect · error

session is closed

Error message

session is closed

What it means

antigravitySession.Send checks the atomic 'alive' flag and refuses to submit a prompt once the session has been closed or the underlying process has exited. It is a lifecycle guard against using a dead session handle.

Source

Thrown at agent/antigravity/session.go:77

	if mode == "default" {
		bridge, err := newAgyPermissionBridge(sessionCtx, as.events)
		if err != nil {
			cancel()
			return nil, fmt.Errorf("antigravity: initialize permission bridge: %w", err)
		}
		as.permissionBridge = bridge
	}

	if resumeID != "" && resumeID != core.ContinueSession {
		as.chatID.Store(resumeID)
	}

	return as, nil
}

func (as *antigravitySession) Send(prompt string, messageID string, images []core.ImageAttachment, files []core.FileAttachment) error {
	if !as.alive.Load() {
		return fmt.Errorf("session is closed")
	}

	// Capture existing chat logs so we can identify a new session on first turn
	preEntries := make(map[string]bool)
	homeDir, err := os.UserHomeDir()
	if err == nil {
		slug := antigravityProjectSlug(as.workDir)
		chatsDir := filepath.Join(homeDir, ".gemini", "tmp", slug, "chats")
		if entries, err := os.ReadDir(chatsDir); err == nil {
			for _, entry := range entries {
				if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".jsonl") {
					preEntries[entry.Name()] = true
				}
			}
		}
	}

	// Save images and files into the workspace

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Start a fresh session via StartSession instead of reusing the closed one.
  2. Check session liveness (if exposed) before Send, or recreate the session on this error.
  3. In platform handlers, catch this error and fall back to creating a new session for the user's next message.
  4. Investigate why the session died earlier (check the error event stream / agy stderr).

Example fix

// before
err := cachedSession.Send(prompt, id, nil, nil)
// after
if err := cachedSession.Send(prompt, id, nil, nil); err != nil && err.Error() == "session is closed" {
    cachedSession, err = agent.StartSession(ctx, opts)
    err = cachedSession.Send(prompt, id, nil, nil)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := session.Send(prompt, id, nil, nil); err != nil {
    if err.Error() == "session is closed" {
        session, err = agent.StartSession(ctx, opts)
        if err == nil { err = session.Send(prompt, id, nil, nil) }
    }
}

Prevention

When it happens

Trigger: Calling Send on a session after Stop()/Close(), after the agy process exited, or after an event-stream terminal event marked the session dead.

Common situations: The engine's session cache retaining an expired session; agy crashing mid-session and the caller retrying Send on the same handle; messages arriving from the platform after the user ran /stop.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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