NousResearch/hermes-agent

Cron jobs failing due to undefined get_fallback_chain

Cluster 36734 · cron. Data as of

Nothing open on GitHub. Fix merged in #56166 on 1 Jul 2026. Check it covers your case.

The short answer

0open issues
0open PRs
4items grouped
Known?
Yes. 4 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #56166. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
Nothing open on GitHub.

All cron jobs were failing with a NameError because get_fallback_chain was not accessible in the job runner. Multiple fix attempts address wiring this function into the cron job runner correctly.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #56166 fix(cron): use shared get_fallback_chain in job runner (#36734)

    merged to main

    files: cron/scheduler.py, tests/cron/test_scheduler.py

    Show the diff
    • cron/scheduler.py
      @@ -41,6 +41,7 @@
       from hermes_constants import get_hermes_home
       from hermes_cli._subprocess_compat import windows_hide_flags
       from hermes_cli.config import load_config, _expand_env_vars
      +from hermes_cli.fallback_config import get_fallback_chain
       from hermes_time import now as _hermes_now
       
       logger = logging.getLogger(__name__)
      @@ -2370,12 +2371,9 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
               except AuthError as auth_exc:
                   # Primary provider auth failed — try fallback chain before giving up.
                   logger.warning("Job '%s': primary auth failed (%s), trying fallback", job_id, auth_exc)
      -            fb = _cfg.get("fallback_providers") or _cfg.get("fallback_model")
      -            fb_list = (fb if isinstance(fb, list) else [fb]) if fb else []
      +            fb_list = get_fallback_chain(_cfg)
                   runtime = None
                   for entry in fb_list:
      -                if not isinstance(entry, dict):
      -                    continue
                       try:
                           fb_kwargs = {"requested": entry.get("provider")}
                           if entry.get("base_url"):
      @@ -2447,7 +2445,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
                       f"(or pin the original values to keep them). See #44585."
                   )
       
      -        fallback_model = _cfg.get("fallback_providers") or _cfg.get("fallback_model") or None
      +        fallback_model = get_fallback_chain(_cfg) or None
               credential_pool = None
               runtime_provider = str(runtime.get("provider") or "").strip().lower()
               if runtime_provider:
    • tests/cron/test_scheduler.py
      @@ -1926,6 +1926,36 @@ def test_fallback_model_env_ref_in_config_yaml_is_expanded(self, tmp_path, monke
                   "config.yaml ${VAR} in fallback_providers was not expanded."
               )
       
      +    def test_fallback_chain_merges_providers_and_legacy_model(self, tmp_path, monkeypatch):
      +        """Cron uses get_fallback_chain so legacy fallback_model is not dropped."""
      +        (tmp_path / "config.yaml").write_text(
      +            "fallback_providers:\n"
      +            "  - provider: openrouter\n"
      +            "    model: gpt-4o-mini\n"
      +            "fallback_model:\n"
      +            "  provider: anthropic\n"
      +            "  model: claude-sonnet-4-6\n"
      +        )
      +
      +        job = {"id": "fb-merge", "name": "fallback merge", "prompt": "hi"}
      +        fake_db = MagicMock()
      +
      +        with patch("cron.scheduler._hermes_home", tmp_path), \
      +             patch("cron.scheduler._resolve_origin", return_value=None), \
      +             patch("dotenv.load_dotenv"), \
      +             patch("hermes_state.SessionDB", return_value=fake_db), \
      +             patch("hermes_cli.runtime_provider.resolve_runtime_provider",
      +                   return_value=self._RUNTIME), \
      +             patch("run_agent.AIAgent") as mock_agent_cls:
      +            mock_agent = MagicMock()
      +            mock_agent.run_conversation.return_value = {"final_response": "ok"}
      +            mock_agent_cls.return_value = mock_agent
      +            run_job(job)
      +
      +        fb = mock_agent_cls.call_args.kwargs.get("fallback_model") or []
      +        models = [e.get("model") for e in fb if isinstance(e, dict)]
      +        assert models == ["gpt-4o-mini", "claude-sonnet-4-6"]
      +
           def test_unexpanded_ref_passthrough_when_var_unset(self, tmp_path, monkeypatch):
               """When the env var is not set, the literal ${VAR} is kept verbatim (not crashed)."""
               (tmp_path / "config.yaml").write_text("model: ${_HERMES_TEST_CRON_UNSET_VAR}\n")

2 PRs closed without merging

From the close comments: merged via another change 1 · partial fix 1

  • #36809 fix(cron): wire get_fallback_chain into job runner (#36734) · merged via another change → 32bc365, #56166, #36734
  • #38718 fix(cron): NameError get_fallback_chain + silent ticker death + tick() blocks (#36734 #36854 #37312) · partial fix → #37312, #39008, #36734, #36854
Closed issues · 1
  • Closed#36734[CRON] All cron jobs fail: NameError: get_fallback_chain is not defined
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.50: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
cron
Merged PRs
#56166
Closed issues
1
Attempts
2 PRs closed without merging
Fix link checked
1 Jul 2026

For your agent

The same facts, typed.