Skip to content

fix:(llmrails): pre-initialize LLMRails.kb to prevent AttributeError on init failure#1823

Open
octo-patch wants to merge 1 commit intoNVIDIA-NeMo:developfrom
octo-patch:fix/issue-1665-llmrails-kb-attr
Open

fix:(llmrails): pre-initialize LLMRails.kb to prevent AttributeError on init failure#1823
octo-patch wants to merge 1 commit intoNVIDIA-NeMo:developfrom
octo-patch:fix/issue-1665-llmrails-kb-attr

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 26, 2026

Fixes #1665

Problem

When LLMRails is initialized, it calls _init_kb() in a background thread via asyncio.run(). If the background thread fails (e.g., asyncio.run() raises a RuntimeError before the coroutine body starts), the thread exits silently — threading.Thread.join() does not propagate thread exceptions. As a result, self.kb is never set on the LLMRails instance.

Any subsequent access to self.kb (including self.runtime.register_action_param("kb", self.kb) at the end of __init__) then raises:

AttributeError: 'LLMRails' object has no attribute 'kb'

This has been reported for Python 3.12+ in LangGraph/LangChain integration scenarios.

Solution

Pre-initialize self.kb = None immediately before launching the background thread. This ensures:

  1. The attribute always exists on the LLMRails instance, even if _init_kb() never runs.
  2. Behavior is consistent with _init_kb() itself, which already sets self.kb = None as its very first statement before any conditional logic.

Testing

  • Existing tests continue to pass (no functional logic changed).
  • The fix is purely defensive initialization that mirrors what _init_kb() already does.

Signed-off-by: Octopus liyuan851277048@icloud.com

Summary by CodeRabbit

  • Bug Fixes
    • Improved knowledge base initialization reliability to prevent potential startup failures.

…lure (fixes NVIDIA-NeMo#1665)

When `_init_kb()` runs in a background thread via `asyncio.run()`, any
failure before the coroutine body executes leaves `self.kb` unset.
Subsequent access to `self.kb` then raises AttributeError instead of
a meaningful error.

Pre-initialize `self.kb = None` before the thread starts so the
attribute always exists, regardless of thread execution outcome.
This is consistent with how `_init_kb()` itself begins by setting
`self.kb = None` before any other logic.

Co-Authored-By: Octopus <liyuan851277048@icloud.com>
Signed-off-by: octo-patch <octo-patch@github.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 26, 2026

Greptile Summary

This PR adds a single defensive line self.kb = None before the background thread that runs _init_kb(), preventing an AttributeError when the thread fails silently (e.g., due to a nested event-loop RuntimeError in Python 3.12+ environments). The fix is minimal and correctly mirrors the first statement already inside _init_kb() itself.

Confidence Score: 5/5

This PR is safe to merge — it is a purely defensive one-line initialization with no functional change to the happy path.

The change adds self.kb = None before a background thread launch, mirroring the identical first statement already inside _init_kb(). No logic is altered for the success path; the failure path is strictly improved. No new risks introduced.

No files require special attention.

Important Files Changed

Filename Overview
nemoguardrails/rails/llm/llmrails.py Adds self.kb = None pre-initialization before the background thread launch to prevent AttributeError when the thread exits before setting the attribute; change is minimal, correct, and mirrors the first line of _init_kb().

Sequence Diagram

sequenceDiagram
    participant C as Caller
    participant R as LLMRails.__init__
    participant T as Background Thread
    participant K as _init_kb()

    C->>R: LLMRails(config, ...)
    R->>R: register_actions(llm_generation_actions)
    Note over R: self.kb = None  ← NEW (pre-init)
    R->>T: Thread(target=asyncio.run, args=(_init_kb(),)).start()
    T->>K: asyncio.run(_init_kb())
    alt _init_kb succeeds
        K->>K: self.kb = None
        K->>K: self.kb = KnowledgeBase(...)
        K->>K: kb.init() / kb.build()
        K-->>T: coroutine completes
        T-->>R: join() returns
        R->>R: register_action_param("kb", self.kb) ← kb is KnowledgeBase
    else _init_kb fails
        K--xT: exception swallowed by thread
        T-->>R: join() returns (silently)
        R->>R: register_action_param("kb", self.kb) ← kb is None (no AttributeError)
    end
    R-->>C: LLMRails instance returned
Loading

Reviews (1): Last reviewed commit: "fix: pre-initialize LLMRails.kb to preve..." | Re-trigger Greptile

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

The change initializes self.kb to None in LLMRails.__init__ before launching the asynchronous _init_kb operation. This ensures the attribute exists prior to registration and prevents AttributeError when accessing kb before async initialization completes.

Changes

Cohort / File(s) Summary
KB Attribute Initialization
nemoguardrails/rails/llm/llmrails.py
Initialize self.kb = None before async knowledge base initialization to prevent race condition where attribute is accessed before _init_kb completes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR directly addresses issue #1665 by pre-initializing self.kb=None before launching the background thread, which prevents AttributeError when asyncio.run() fails and _init_kb never runs.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the AttributeError issue in #1665; the PR only adds defensive initialization of self.kb and does not introduce unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Test Results For Major Changes ✅ Passed PR contains minor defensive initialization changes (+2 lines) fixing AttributeError. Existing tests continue to pass; no functional logic altered.
Title check ✅ Passed The title accurately describes the main change: pre-initializing LLMRails.kb to prevent AttributeError on initialization failure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Pouyanpi Pouyanpi changed the title fix: pre-initialize LLMRails.kb to prevent AttributeError on init failure fix:(llmrails): pre-initialize LLMRails.kb to prevent AttributeError on init failure Apr 27, 2026
Copy link
Copy Markdown
Collaborator

@Pouyanpi Pouyanpi left a comment

Choose a reason for hiding this comment

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

Thank you @octo-patch for fixing the issue👍🏻

@Pouyanpi Pouyanpi force-pushed the develop branch 4 times, most recently from a6be550 to c69efe5 Compare May 6, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: LLMRails has not attribute kb when trying to use Nemo Guardrails with Langgraph

2 participants