Skip to content

fix(doctor): handle SecretRef objects in memory search apiKey check#35464

Closed
jmzlx wants to merge 2 commits intoopenclaw:mainfrom
jmzlx:fix/doctor-secretref-trim
Closed

fix(doctor): handle SecretRef objects in memory search apiKey check#35464
jmzlx wants to merge 2 commits intoopenclaw:mainfrom
jmzlx:fix/doctor-secretref-trim

Conversation

@jmzlx
Copy link
Copy Markdown

@jmzlx jmzlx commented Mar 5, 2026

Problem

openclaw doctor crashes at the end of its run:

TypeError: resolved?.remote?.apiKey?.trim is not a function

resolveMemorySearchConfig() may return an unresolved SecretRef object for apiKey when configured via environment variable reference. The doctor command does not resolve secrets before calling .trim().

Fix

Guard with typeof check before calling .trim():

const rawApiKey = resolved?.remote?.apiKey;
const hasRemoteApiKey = Boolean(
  typeof rawApiKey === "string" ? rawApiKey.trim() : rawApiKey,
);

Verified

  • Gateway runtime resolves SecretRef correctly (unaffected)
  • openclaw doctor crashes reproducibly at doctor-memory-search.ts:29
  • Linter passes (0 warnings, 0 errors)

Fixes #35444.

resolveMemorySearchConfig() may return an unresolved SecretRef object
for apiKey (e.g. when configured via env var reference). Calling
.trim() on a non-string value throws TypeError.

Guard with typeof check before trimming.

Fixes openclaw#35444.
@jmzlx jmzlx marked this pull request as ready for review March 5, 2026 04:53
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 5, 2026

Greptile Summary

This PR fixes a crash in openclaw doctor by guarding the .trim() call on apiKey with a typeof string check, preventing a TypeError when resolveMemorySearchConfig returns an unresolved SecretRef object instead of a plain string.

Fix quality: The fix is correct and minimal. SecretRef objects are truthy and are appropriately treated as a configured API key, consistent with how the gateway runtime handles them. The typeof guard preserves existing behavior for plain strings, empty strings, null, and undefined.

Type safety gap: The apiKey field in src/agents/memory-search.ts is typed as string | undefined, which doesn't reflect that it can carry a SecretRef at runtime. Updating that type annotation would let TypeScript catch similar unsafe calls automatically at future call sites, preventing recurrence.

Confidence Score: 5/5

  • This PR is safe to merge — it is a narrow, targeted bug fix with no risk of regression.
  • The change is a single-file, two-line patch that adds a defensive type guard. The logic is straightforward, all existing code paths are preserved, and the fix directly addresses the reproducible crash described in the issue. The only pre-existing concern is the type annotation gap in src/agents/memory-search.ts, which this PR works around but doesn't require fixing as a prerequisite.
  • No files require special attention, though src/agents/memory-search.ts has a pre-existing type annotation that could be improved in a follow-up PR.

Last reviewed commit: 666e261

Comment on lines +29 to +30
const rawApiKey = resolved?.remote?.apiKey;
const hasRemoteApiKey = Boolean(typeof rawApiKey === "string" ? rawApiKey.trim() : rawApiKey);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix correctly guards against calling .trim() on SecretRef objects at runtime. However, the apiKey field in src/agents/memory-search.ts (line 15) is still typed as apiKey?: string, which doesn't reflect that it can carry an unresolved SecretRef object.

Updating the type to apiKey?: string | SecretRef (or similar) would let TypeScript catch future call sites that unsafely assume apiKey is always a plain string, preventing recurrence of this class of crash elsewhere in the codebase.

This is a pre-existing type annotation gap that this PR works around. Closing it would strengthen type safety for memory search config handling.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/doctor-memory-search.ts
Line: 29-30

Comment:
The fix correctly guards against calling `.trim()` on `SecretRef` objects at runtime. However, the `apiKey` field in `src/agents/memory-search.ts` (line 15) is still typed as `apiKey?: string`, which doesn't reflect that it can carry an unresolved `SecretRef` object.

Updating the type to `apiKey?: string | SecretRef` (or similar) would let TypeScript catch future call sites that unsafely assume `apiKey` is always a plain string, preventing recurrence of this class of crash elsewhere in the codebase.

This is a pre-existing type annotation gap that this PR works around. Closing it would strengthen type safety for memory search config handling.

How can I resolve this? If you propose a fix, please make it concise.

…undary

The apiKey field in ResolvedMemorySearchConfig can carry an unresolved
SecretRef object at runtime, but was typed as string | undefined.

- Update type annotation to string | SecretRef in memory-search.ts
- Resolve SecretRef → string at the boundary in manager.ts and
  manager-sync-ops.ts before passing to createEmbeddingProvider
- EmbeddingProviderOptions.remote.apiKey stays as string (expects
  resolved values)

Addresses review feedback from greptile-apps on the typeof guard.
@jmzlx
Copy link
Copy Markdown
Author

jmzlx commented Mar 5, 2026

Addressed in 5157062 — widened apiKey type to string | SecretRef in ResolvedMemorySearchConfig, and added SecretRef→string resolution at the boundary in both manager.ts and manager-sync-ops.ts before passing to createEmbeddingProvider.

TypeScript now catches any future call site that unsafely assumes apiKey is always a plain string.

tsc --noEmit clean, oxlint --type-aware 0 warnings/errors.

@openclaw-barnacle openclaw-barnacle bot added commands Command implementations agents Agent runtime and tooling size: XS labels Mar 5, 2026
@joshavant
Copy link
Copy Markdown
Contributor

Thanks for the contribution here, and for helping narrow down the SecretRef doctor crash.

We merged #36835, which supersedes this PR and fixes the broader doctor/memory SecretRef surface in one place, including the related runtime embedding paths.

I’m closing this as superseded by #36835, but I appreciate the fix and the investigation that went into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling commands Command implementations size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openclaw doctor crashes with TypeError on SecretRef/vault-resolved apiKey values

2 participants