# NousResearch/hermes-agent · Cron jobs failing due to undefined get_fallback_chain

## Open now

- 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.

## TL;DR

- 4 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 2 PR(s) closed without merging.
- A fix was merged to main in PR #56166. Verify it addresses your case.
- **Recommended:** read PR #56166 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.50`: the share of member 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.

## Closed / duplicate issues

- #36734: \[CRON\] All cron jobs fail: NameError: get_fallback_chain is not defined

## Prior & competing PRs

- **#38718: fix(cron): NameError get_fallback_chain + silent ticker death + tick() blocks (#36734 #36854 #37312)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `partial_fix`; implication `needs_llm`; refs `#37312`, `#39008`, `#36734`, `#36854`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#56166: fix(cron): use shared get_fallback_chain in job runner (#36734)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `cron/scheduler.py`, `tests/cron/test_scheduler.py`
  - fix hunks:
  - `cron/scheduler.py`

    ```diff
    @@ -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__)
    ```

    ```diff
    @@ -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"):
    ```

    ```diff
    @@ -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`

    ```diff
    @@ -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")
    ```
- **#36809: fix(cron): wire get_fallback_chain into job runner (#36734)**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `32bc36522`, `#56166`, `#36734`

## Fix status

- Merged to main in PR #56166 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-01`.
- Subsystem: `cron`
