{"record":{"id":"f84f1b7c03fe8cc1","repo":"tinyhumansai/openhuman","slug":"agent-definition-not-found-in-registry","errorCode":null,"errorMessage":"agent definition '{}' not found in registry","messagePattern":"agent definition '(.+?)' not found in registry","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/harness/session/builder/factory.rs","lineNumber":1415,"sourceCode":"    if agent_id == \"orchestrator\" {\n        // Orchestrator is allowed to be missing from every source (legacy\n        // path, tests, pre-startup) — fall back to default behaviour.\n        log::debug!(\n            \"[agent::builder] orchestrator definition not in any registry — using legacy \\\n             default prompt + filter\"\n        );\n        return Ok(None);\n    }\n\n    if registry.is_none() {\n        return Err(anyhow::anyhow!(\n            \"AgentDefinitionRegistry is not initialised — cannot resolve agent '{}'. Call \\\n             AgentDefinitionRegistry::init_global at startup.\",\n            agent_id\n        ));\n    }\n\n    Err(anyhow::anyhow!(\n        \"agent definition '{}' not found in registry\",\n        agent_id\n    ))\n}\n\nfn definition_disallows_tool(disallowed: &[String], name: &str) -> bool {\n    disallowed.iter().any(|entry| {\n        if let Some(prefix) = entry.strip_suffix('*') {\n            name.starts_with(prefix)\n        } else {\n            entry == name\n        }\n    })\n}\n\n/// Which tool-call dialect a session speaks to its provider.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum DispatcherKind {","sourceCodeStart":1397,"sourceCodeEnd":1433,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/harness/session/builder/factory.rs#L1397-L1433","documentation":"resolve_target_definition (src/openhuman/agent/harness/session/builder/factory.rs:1415) is the last-resort miss: the agent id was not in the global AgentDefinitionRegistry, not in the config-backed custom registry (config.agent_registry.entries), and is not \"orchestrator\" (which may legally fall back to legacy defaults returning Ok(None)). Note the distinct sibling error when registry.is_none(): that one says the registry was never initialized — this one means it was initialized and simply lacks the id.","triggerScenarios":"Building a session with a typo'd/stale agent_id; an id that existed in a previous version or a different workspace's overrides; a custom id present in neither the harness registry nor config.agent_registry.entries; an agent compiled out by a feature-gated slim build.","commonSituations":"Persisted thread metadata referencing an agent id deleted by a workspace override cleanup; downstream code hardcoding an agent id that a rename/feature-gate removed; per-workspace overrides not loaded because init_global ran against a different workspace_dir.","solutions":["Verify the id against registry.list() (or the debug prompt dump) and fix the typo/rename.","If it is a custom agent, define it under config.agent_registry.entries or as a workspace override so one of the two lookup sources finds it.","Confirm AgentDefinitionRegistry::init_global ran against the same workspace_dir your session uses (mismatched workspaces load different override sets).","If the binary is a slim/feature-gated build, rebuild with the feature set that embeds that agent.","Do not shadow with \"orchestrator\" — only that exact id is allowed to resolve to legacy defaults."],"exampleFix":"// before\nlet agent = build_session_agent(&config, \"integration_agent\").await?; // typo\n// after\nlet agent = build_session_agent(&config, \"integrations_agent\").await?;","handlingStrategy":"validation","validationCode":"fn agent_id_resolves(config: &Config, agent_id: &str) -> bool {\n    if let Some(reg) = AgentDefinitionRegistry::global() {\n        if reg.get(agent_id).is_some() {\n            return true;\n        }\n    }\n    // second source: config-backed custom agents\n    crate::openhuman::agent::registry::find_custom_in_config(config, agent_id).is_some()\n        || agent_id == \"orchestrator\" // legacy fallback allowed to resolve to None\n}","typeGuard":"fn agent_id_resolves(config: &Config, agent_id: &str) -> bool {\n    AgentDefinitionRegistry::global().map(|r| r.get(agent_id).is_some()).unwrap_or(false)\n        || crate::openhuman::agent::registry::find_custom_in_config(config, agent_id).is_some()\n}","tryCatchPattern":"match resolve_target_definition(&config, agent_id).await {\n    Ok(Some(def)) => Ok(def),\n    Ok(None) => Ok(/* orchestrator legacy default build */),\n    Err(e) if e.to_string().contains(\"not found in registry\") => {\n        // Not a retry case: fix the id (registry.list() / dump-all), register\n        // the custom agent in config.agent_registry.entries or a workspace\n        // override, or confirm the build embeds it.\n    }\n    Err(e) => Err(e), // the 'not initialised' sibling needs init_global at startup\n}","preventionTips":["Resolve agent ids against registry.list() at startup and fail fast on unknown ids.","Register custom agents in config.agent_registry.entries or workspace overrides so both lookup sources are covered.","Ensure AgentDefinitionRegistry::init_global runs at startup against the same workspace sessions use.","When renaming/removing agents, migrate persisted references (thread metadata, hardcoded ids)."],"tags":["rust","registry","agent-definitions","not-found","session-builder"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}