{"record":{"id":"10fd8b5e6a184d4f","repo":"langchain-ai/deepagents","slug":"unresolved-source-message-plugin-id-entry-rejec","errorCode":null,"errorMessage":"{unresolved_source_message(plugin_id, entry, rejections)}","messagePattern":"\\{unresolved_source_message\\(plugin_id, entry, rejections\\)\\}","errorType":"exception","errorClass":"MarketplaceError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/plugins/discovery.py","lineNumber":226,"sourceCode":"    writes `installed_plugins.json`, and enables the plugin.\n\n    Args:\n        plugin_id: Plugin id in `{name}@{marketplace}` form.\n\n    Returns:\n        Discovered plugin instance loaded from the cache path.\n\n    Raises:\n        MarketplaceError: If the marketplace/plugin cannot be resolved, the\n            source is unsupported, or the cached plugin fails to load.\n    \"\"\"\n    load_installed_plugins(strict=True)\n    load_enabled_plugin_ids(strict=True)\n    marketplace, entry = _resolve_marketplace_and_entry(plugin_id)\n    rejections: list[str] = []\n    source_root = materialize_plugin_source(marketplace, entry, rejections=rejections)\n    if source_root is None:\n        raise MarketplaceError(unresolved_source_message(plugin_id, entry, rejections))\n\n    try:\n        manifest, _manifest_path, manifest_warnings = load_manifest(\n            source_root, fallback_name=entry.name\n        )\n    except PluginManifestError as exc:\n        msg = f\"Cannot install {plugin_id}: {exc}\"\n        raise MarketplaceError(msg) from exc\n\n    for warning in manifest_warnings:\n        logger.debug(\"Plugin install warning for %s: %s\", plugin_id, warning)\n\n    version = manifest.version if manifest is not None else None\n    cache_path = cache_and_register_plugin(\n        plugin_id,\n        source_root,\n        version=version,\n        validate=partial(","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/plugins/discovery.py#L208-L244","documentation":"install_plugin materializes the plugin's source from the marketplace into a local root; when materialize_plugin_source returns None it populates `rejections` explaining why candidate sources were rejected, and install_plugin raises MarketplaceError with unresolved_source_message summarizing them. It means no valid local copy of the plugin source could be produced from the marketplace entry.","triggerScenarios":"materialize_plugin_source fails for all candidate sources — e.g. checkout/copy refused (symlink escaping the plugin directory, missing files), cache write failure, or the marketplace entry pointing at a nonexistent source path; the rejections list is embedded in the message.","commonSituations":"A plugin repo containing symlinks that point outside the plugin (deliberately rejected for safety); a marketplace install_location deleted or moved on disk; partial/corrupted marketplace checkout; network fetch failures during materialization.","solutions":["Read the unresolved_source_message — the embedded rejections name each rejected source and reason.","Re-add or refresh the marketplace so its source location is intact and current.","Remove forbidden symlinks (or point them inside the plugin) in the plugin source.","Check the cache/install directories for permissions and disk space.","If the source lives remotely, verify the fetch (URL reachable, credentials valid) then retry."],"exampleFix":"// before (plugin dir contains a symlink escaping the plugin)\nsrc -> /usr/share/evil   # rejected\n# after\nln -s ./vendor src       # symlink stays inside the plugin\n$ dcode plugin install widget@internal","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef source_root_sane(root: Path) -> bool:\n    if not root.is_dir():\n        return False\n    for link in root.rglob(\"*\"):\n        if link.is_symlink():\n            target = link.resolve()\n            if not target.is_relative_to(root.resolve()):\n                return False  # symlink escapes plugin dir -> will be rejected\n    return True\n\nassert source_root_sane(Path(\"plugins/widget\"))","typeGuard":"def symlink_safe(root: Path) -> bool:\n    root_resolved = root.resolve()\n    return all(\n        not p.is_symlink() or p.resolve().is_relative_to(root_resolved)\n        for p in root.rglob(\"*\")\n    )","tryCatchPattern":"try:\n    install_plugin(\"widget@internal\")\nexcept MarketplaceError as exc:\n    print(\"source unresolved:\", exc)  # rejections list explains each rejected candidate\n    # remediate: refresh marketplace, fix symlinks, check disk/permissions","preventionTips":["Keep all symlinks inside the plugin directory.","Refresh/re-add marketplaces so install_location stays valid.","Check disk space and write permissions on cache dirs.","Verify remote sources are fetchable before installing.","Inspect the rejections in the message — they name each cause."],"tags":["plugin-install","source-materialization","symlink"],"backgroundTag":"plugin-source-unresolved","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}