Skip to content

fix(models): guard optional model input capabilities #42096

Merged
hydro13 merged 6 commits intoopenclaw:mainfrom
andyliu:andy/fix-model-input-nullcheck
Mar 11, 2026
Merged

fix(models): guard optional model input capabilities #42096
hydro13 merged 6 commits intoopenclaw:mainfrom
andyliu:andy/fix-model-input-nullcheck

Conversation

@andyliu
Copy link
Copy Markdown
Contributor

@andyliu andyliu commented Mar 10, 2026

Fix crash when model.input is missing by guarding image-capability checks with optional chaining.

Summary

• Problem: Some code paths assume model.input is always defined and call model.input.includes("image"), which throws when custom/OpenAI-compatible providers return models without an input field.
• Why it matters: This can crash or break downstream flows (e.g. model scanning / compaction paths), forcing fallbacks and degrading reliability for custom providers.
• What changed: Use optional chaining (model.input?.includes("image")) and safe defaults (model.input ?? []) when checking/augmenting image capabilities.
• What did NOT change (scope boundary): No changes to provider routing, network calls, token handling, or model selection logic beyond guarding undefined fields.

Change Type (select all)

• [x] Bug fix
• [ ] Feature
• [ ] Refactor
• [ ] Docs
• [ ] Security hardening
• [ ] Chore/infra

Scope (select all touched areas)

• [ ] Gateway / orchestration
• [ ] Skills / tool execution
• [ ] Auth / tokens
• [ ] Memory / storage
• [ ] Integrations
• [x] API / contracts
• [ ] UI / DX
• [ ] CI/CD / infra

Linked Issue/PR

Closes #42068
• Related #

User-visible / Behavior Changes

None (internal robustness improvement). Prevents crashes when model.input is absent.

Security Impact (required)

• New permissions/capabilities? No
• Secrets/tokens handling changed? No
• New/changed network calls? No
• Command/tool execution surface changed? No
• Data access scope changed? No
• If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

• OS: macOS (Darwin arm64)
• Runtime/container: Node.js + pnpm (local dev)
• Model/provider: custom OpenAI-compatible providers (e.g. MiniMax via openai-completions)
• Integration/channel (if any): N/A
• Relevant config (redacted): N/A

Steps

  1. Use a custom/OpenAI-compatible provider where model.input may be undefined.
  2. Trigger code paths that check image capability (previously model.input.includes("image")).
  3. Observe no crash.

Expected

• No TypeError when model.input is missing.

Actual

• Previously: TypeError: Cannot read properties of undefined (reading 'includes').

Evidence

• [x] Failing test/log before + passing after
• Ran: pnpm vitest src/agents/model-scan.test.ts

Human Verification (required)

• Verified scenarios:
• Guarded image capability checks don’t crash when model.input is undefined.
• Edge cases checked:
• model.input undefined + ensureImageInput path.
• What you did not verify:
• End-to-end run against the reporter’s exact custom provider config (covered by unit tests + defensive coding).

Review Conversations

• [x] I replied to or resolved every bot review conversation I addressed in this PR.
• [x] I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

• Backward compatible? Yes
• Config/env changes? No
• Migration needed? No

Failure Recovery (if this breaks)

• How to disable/revert this change quickly: revert this PR/commit.
• Files/config to restore:
• src/agents/model-scan.ts
• src/agents/tools/image-tool.helpers.ts
• src/commands/models/list.table.ts
• Known bad symptoms reviewers should watch for:
• Regression in image-capability detection (should remain unchanged except now null-safe).

Risks and Mitigations

• Risk: None meaningful; change is null-safety only.
• Mitigation: Unit test coverage for model-scan path + minimal surface change.

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

andyliu commented Mar 10, 2026

Closes #42068.

This makes image-capability checks null-safe for custom/OpenAI-compatible providers where model.input may be undefined (replacing .includes("image") with optional chaining + safe defaults). Verified locally with pnpm vitest src/agents/model-scan.test.ts.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR adds null-safety guards (?. optional chaining and ?? [] defaults) across three files to prevent TypeError: Cannot read properties of undefined (reading 'includes') crashes when model.input is absent — a scenario that can occur with custom/OpenAI-compatible providers. The core fix in model-scan.ts is correct and directly addresses the reported crash.

  • src/agents/model-scan.ts: The ensureImageInput function and the imageResult gate in scanOpenRouterModels are now safe when model.input is undefined. Note that within scanOpenRouterModels model.input is always populated by parseModality(entry.modality) (which always returns an array), so the gate guard is purely defensive for that call site — but it correctly protects callers of ensureImageInput from external code paths.
  • src/agents/tools/image-tool.helpers.ts: The ?. added at line 80 is redundant because the preceding Array.isArray(m?.input) check already guarantees a defined array at that point. Harmless, but slightly noisy.
  • src/commands/models/list.table.ts: ModelRow.input is typed as non-optional string; optional chaining on it is unnecessary per the type definition. If input can genuinely be undefined at runtime, the ModelRow type in list.types.ts should be updated to reflect that, rather than silently hiding it at the call site.

Confidence Score: 4/5

  • Safe to merge — the fix is minimal, null-safety only, and directly resolves a real crash path with no behavioral regressions for well-formed inputs.
  • The primary crash fix in model-scan.ts is correct and well-scoped. Two minor style issues exist: an optional chain on a non-optional string type in list.table.ts (which may mask a missing type update), and a redundant ?. in image-tool.helpers.ts after an Array.isArray guard. Neither introduces a bug. Score is 4 rather than 5 due to the unresolved type-accuracy question in ModelRow.
  • src/commands/models/list.table.ts — check whether ModelRow.input type should be updated to string | undefined.

Last reviewed commit: f00654f

@openclaw-barnacle openclaw-barnacle bot removed the commands Command implementations label Mar 10, 2026
@andyliu
Copy link
Copy Markdown
Contributor Author

andyliu commented Mar 10, 2026

FYI: addressed Greptile nits — removed redundant optional chaining after Array.isArray guards, and reverted optional chaining on ModelRow.input (non-optional by type). Core null-safety fix for model.input remains in model-scan.ts.

Copy link
Copy Markdown
Contributor

@hydro13 hydro13 left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @andyliu!

After tracing the repro in #42068, I think this fix lands in the wrong code path. The crash reported there happens in convertMessages() inside @mariozechner/pi-ai when an openai-completions provider returns a model without an input field ,that path still calls model.input.includes("image") without a null guard after this change.

The fixes in model-scan.ts lines 328 and 475 harden the OpenRouter scan/probe path, where model.input is already constructed from parseModality(entry.modality) anyway, so the guard there is defensive but doesn't address the reported crash.

Would you be able to extend the fix to cover the convertMessages() path as well? Happy to re-review once that's in.

@andyliu
Copy link
Copy Markdown
Contributor Author

andyliu commented Mar 10, 2026

Thanks for the PR @andyliu!

After tracing the repro in #42068, I think this fix lands in the wrong code path. The crash reported there happens in convertMessages() inside @mariozechner/pi-ai when an openai-completions provider returns a model without an input field ,that path still calls model.input.includes("image") without a null guard after this change.

The fixes in model-scan.ts lines 328 and 475 harden the OpenRouter scan/probe path, where model.input is already constructed from parseModality(entry.modality) anyway, so the guard there is defensive but doesn't address the reported crash.

Would you be able to extend the fix to cover the convertMessages() path as well? Happy to re-review once that's in.

Good catch — you’re right that #42068 crashes inside @mariozechner/pi-ai’s openai-completions convertMessages().

I updated the PR to patch @mariozechner/[email protected] via pnpm patchedDependencies, switching model.input includes checks to optional chaining (model.input?.includes("image")) in the openai-completions provider (and a couple of similar call sites). This should cover the reported crash path. Happy to adjust if you’d prefer upstreaming this to pi-ai instead of carrying a patch.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f1f328e58

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@andyliu andyliu force-pushed the andy/fix-model-input-nullcheck branch from faa4d47 to 4a63f1f Compare March 11, 2026 04:53
@andyliu andyliu force-pushed the andy/fix-model-input-nullcheck branch from abb35b6 to 2d7712c Compare March 11, 2026 06:02
@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation channel: telegram Channel integration: telegram gateway Gateway runtime cli CLI command changes commands Command implementations docker Docker and sandbox tooling size: L and removed size: S labels Mar 11, 2026
@andyliu andyliu force-pushed the andy/fix-model-input-nullcheck branch from 2d7712c to 46672f7 Compare March 11, 2026 06:07
andyliu and others added 3 commits March 11, 2026 13:36
Ensure discovered/configured models always have a safe input[] (defaults to text) so downstream pi-ai convertMessages doesn't crash when a provider omits input.
@hydro13 hydro13 force-pushed the andy/fix-model-input-nullcheck branch from 03d15be to d398fa0 Compare March 11, 2026 12:36
@openclaw-barnacle openclaw-barnacle bot added size: S and removed docs Improvements or additions to documentation channel: telegram Channel integration: telegram app: ios App: ios app: macos App: macos gateway Gateway runtime cli CLI command changes scripts Repository scripts commands Command implementations docker Docker and sandbox tooling size: XL labels Mar 11, 2026
@hydro13 hydro13 merged commit 10e6e27 into openclaw:main Mar 11, 2026
29 checks passed
@hydro13
Copy link
Copy Markdown
Contributor

hydro13 commented Mar 11, 2026

Merged via squash.

Thanks @andyliu!

Treedy2020 pushed a commit to Treedy2020/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 11, 2026
* main: (49 commits)
  fix(agents): add nodes to owner-only tool policy fallbacks
  fix(gateway): propagate real gateway client into plugin subagent runtime
  fix(gateway): enforce caller-scope subsetting in device.token.rotate
  fix(terminal): stabilize skills table width across Terminal.app and iTerm (openclaw#42849)
  fix(models): guard optional model input capabilities  (openclaw#42096)
  macOS/onboarding: prompt for remote gateway auth tokens (openclaw#43100)
  fix(macos): use foundationValue when serializing browser proxy POST body (openclaw#43069)
  feat(ios): add local beta release flow (openclaw#42991)
  docs(changelog): update context pruning PR reference
  fix(context-pruning): cover image-only tool-result pruning
  fix(context-pruning): prune image-containing tool results instead of skipping them (openclaw#41789)
  fix(agents): include azure-openai in Responses API store override (openclaw#42934)
  fix(telegram): fall back on ambiguous first preview sends
  fix(telegram): prevent duplicate messages with slow LLM providers (openclaw#41932)
  Providers: add Opencode Go support (openclaw#42313)
  fix(sandbox): sanitize Docker env before marking OPENCLAW_CLI (openclaw#42256)
  macOS: add chat model selector and persist thinking (openclaw#42314)
  fix: clear pnpm prod audit vulnerabilities
  fix(build): restore full gate
  fix(gateway): split conversation reset from admin reset
  ...
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
ahelpercn pushed a commit to ahelpercn/openclaw that referenced this pull request Mar 12, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
Ruijie-Ysp pushed a commit to Ruijie-Ysp/clawdbot that referenced this pull request Mar 12, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
leozhengliu-pixel pushed a commit to leozhengliu-pixel/openclaw that referenced this pull request Mar 13, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
plabzzxx pushed a commit to plabzzxx/openclaw that referenced this pull request Mar 13, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
Interstellar-code pushed a commit to Interstellar-code/operator1 that referenced this pull request Mar 16, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13

(cherry picked from commit 10e6e27)
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
t--becker pushed a commit to t--becker/openclaw that referenced this pull request Mar 19, 2026
Merged via squash.

Prepared head SHA: d398fa0
Co-authored-by: andyliu <[email protected]>
Co-authored-by: hydro13 <[email protected]>
Reviewed-by: @hydro13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

model.input.includes() crashes for custom providers without input field

2 participants