chenhg5/cc-connect · error

%s

Error message

%s

What it means

After the kimi CLI process exits, readLoop checks the wait error; on non-zero exit with non-empty stderr it logs the failure and emits core.EventError whose message is exactly the trimmed stderr text (`fmt.Errorf("%s", stderrMsg)`). The message content is kimi's own diagnostic output, so the concrete cause (auth, quota, bad flag) is embedded in the error string.

Source

Thrown at agent/kimi/session.go:308

			break
		}
	}

	if scanErr != nil {
		slog.Error("kimiSession: scanner error", "error", scanErr)
		evt := core.Event{Type: core.EventError, Error: fmt.Errorf("read stdout: %w", scanErr)}
		select {
		case ks.events <- evt:
		case <-ks.ctx.Done():
			return
		}
	}

	if waitErr != nil {
		stderrMsg := strings.TrimSpace(stderrBuf.String())
		if stderrMsg != "" {
			slog.Error("kimiSession: process failed", "error", waitErr, "stderr", stderrMsg)
			evt := core.Event{Type: core.EventError, Error: fmt.Errorf("%s", stderrMsg)}
			select {
			case ks.events <- evt:
			case <-ks.ctx.Done():
				return
			}
			return
		}
	}

	// Flush any remaining pending messages as text and send result event.
	ks.flushPendingAsText()
	evt := core.Event{Type: core.EventResult, SessionID: ks.CurrentSessionID(), Done: true}
	select {
	case ks.events <- evt:
	case <-ks.ctx.Done():
	}
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the event's Error text — it is kimi's stderr and names the real cause; act on that (fix key, quota, or flags).
  2. Reproduce manually in the workDir: `kimi --prompt "test"` and compare stderr.
  3. Align CLI version with the adapter: upgrade/downgrade kimi or update flag construction in agent/kimi/session.go.
  4. Verify credentials/env in the daemon context (systemd Environment= / EnvironmentFile) so the API key is actually present.

Example fix

// symptom
$ kimi --prompt "hi"
Error: unauthorized: invalid api key

// fix for daemons
# /etc/systemd/system/cc-connect.service
[Service]
EnvironmentFile=/etc/cc-connect/env  # contains KIMI_API_KEY=...
Defensive patterns

Strategy: try-catch

Validate before calling

// validate CLI + credentials before opening sessions
out, err := exec.Command(kimiCmd, "--version").CombinedOutput()
if err != nil {
    return fmt.Errorf("kimi CLI unusable: %v: %s", err, out)
}
// ensure API key present in this process env
if os.Getenv("KIMI_API_KEY") == "" {
    return errors.New("KIMI_API_KEY not set for daemon environment")
}

Type guard

func isKimiProcessFailure(err error) bool {
    return err != nil && !strings.Contains(err.Error(), "session is closed")
} // event Error text is kimi's raw stderr — inspect it for auth/quota causes

Try / catch

for evt := range sess.Events() {
    if evt.Type == core.EventError {
        msg := evt.Error.Error()
        switch {
        case strings.Contains(msg, "unauthorized"), strings.Contains(msg, "api key"):
            fixCredentialsAndRecreate()
        case strings.Contains(msg, "quota"), strings.Contains(msg, "rate limit"):
            backoffAndRetry()
        default:
            surfaceToUser(msg)
        }
    }
}

Prevention

When it happens

Trigger: The kimi CLI exits non-zero while handling a prompt: invalid/missing API key, quota or rate limit exhausted, unsupported/renamed CLI flags, incompatible CLI version, or backend/network failure reported by the CLI.

Common situations: Expired or missing kimi API key in the daemon environment; kimi CLI upgraded with changed flags that this adapter still passes; hitting plan quota mid-session; network outage reaching the kimi backend.

Related errors


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