diff --git a/lib/cli/src/crewai_cli/deploy/validate.py b/lib/cli/src/crewai_cli/deploy/validate.py index e75c813ec..0b2564d24 100644 --- a/lib/cli/src/crewai_cli/deploy/validate.py +++ b/lib/cli/src/crewai_cli/deploy/validate.py @@ -172,9 +172,7 @@ class DeployValidator: except Exception: return False crewai_config = get_crewai_project_config(data) - return crewai_config.get("type") == "crew" and bool( - crewai_config.get("definition", "").strip() - ) + return crewai_config.get("type") == "crew" and "definition" in crewai_config def run(self) -> list[ValidationResult]: """Run all checks. Later checks are skipped when earlier ones make diff --git a/lib/cli/tests/deploy/test_validate.py b/lib/cli/tests/deploy/test_validate.py index fec541dbb..31ecb0c8b 100644 --- a/lib/cli/tests/deploy/test_validate.py +++ b/lib/cli/tests/deploy/test_validate.py @@ -569,6 +569,22 @@ def test_is_json_crew_false_for_declared_crew_without_definition(tmp_path): assert DeployValidator(project_root=tmp_path)._is_json_crew is False +def test_json_crew_non_string_definition_reports_invalid_definition( + tmp_path: Path, +) -> None: + (tmp_path / "pyproject.toml").write_text( + '[project]\nname = "demo"\nversion = "0.1.0"\n\n' + '[tool.crewai]\ntype = "crew"\ndefinition = ["crew.jsonc"]\n' + ) + + v = DeployValidator(project_root=tmp_path) + v.run() + + finding = next(r for r in v.results if r.code == "invalid_crew_definition") + assert finding.severity is Severity.ERROR + assert "must be a string" in finding.detail + + def test_is_json_crew_false_without_pyproject(tmp_path): (tmp_path / "crew.jsonc").write_text("{}") diff --git a/lib/crewai-core/src/crewai_core/project.py b/lib/crewai-core/src/crewai_core/project.py index 18fc68a77..9c7e6a33e 100644 --- a/lib/crewai-core/src/crewai_core/project.py +++ b/lib/crewai-core/src/crewai_core/project.py @@ -71,9 +71,20 @@ def configured_project_definition( if crewai_config.get("type") != project_type: return None - definition = crewai_config.get("definition", "").strip() - if not definition: + if "definition" not in crewai_config: return None + raw_definition = crewai_config["definition"] + if not isinstance(raw_definition, str): + raise ProjectDefinitionError( + "[tool.crewai] definition must be a string project-local path; " + f"got {raw_definition!r}." + ) + + definition = raw_definition.strip() + if not definition: + raise ProjectDefinitionError( + "[tool.crewai] definition must be a non-empty project-local path." + ) return resolve_project_definition_path(definition=definition, project_root=root) diff --git a/lib/crewai-core/tests/test_smoke.py b/lib/crewai-core/tests/test_smoke.py index 76414d835..3decdaa73 100644 --- a/lib/crewai-core/tests/test_smoke.py +++ b/lib/crewai-core/tests/test_smoke.py @@ -139,6 +139,42 @@ def test_configured_project_definition_rejects_project_escape(tmp_path: Path) -> ) +def test_configured_project_definition_rejects_non_string_definition( + tmp_path: Path, +) -> None: + with pytest.raises(project.ProjectDefinitionError, match="must be a string"): + project.configured_project_definition( + "crew", + pyproject_data={ + "tool": { + "crewai": { + "type": "crew", + "definition": ["crew.jsonc"], + } + } + }, + project_root=tmp_path, + ) + + +def test_configured_project_definition_rejects_empty_definition( + tmp_path: Path, +) -> None: + with pytest.raises(project.ProjectDefinitionError, match="non-empty"): + project.configured_project_definition( + "crew", + pyproject_data={ + "tool": { + "crewai": { + "type": "crew", + "definition": " ", + } + } + }, + project_root=tmp_path, + ) + + def test_core_telemetry_skips_duplicate_tracer_provider( monkeypatch: pytest.MonkeyPatch, ) -> None: diff --git a/lib/crewai/src/crewai/utilities/reset_memories.py b/lib/crewai/src/crewai/utilities/reset_memories.py index 83ad0747c..2470454dc 100644 --- a/lib/crewai/src/crewai/utilities/reset_memories.py +++ b/lib/crewai/src/crewai/utilities/reset_memories.py @@ -137,3 +137,4 @@ def reset_memories_command( except Exception as e: click.echo(f"An unexpected error occurred: {e}", err=True) + raise SystemExit(1) from e diff --git a/lib/crewai/tests/cli/test_cli.py b/lib/crewai/tests/cli/test_cli.py index b4e23cc95..387e3bb3d 100644 --- a/lib/crewai/tests/cli/test_cli.py +++ b/lib/crewai/tests/cli/test_cli.py @@ -280,6 +280,7 @@ def test_reset_invalid_json_crew_blocks_reset( mock_load_crew.assert_called_once_with((tmp_path / "crew.jsonc").resolve()) mock_crew.reset_memories.assert_not_called() + assert result.exit_code != 0 assert "An unexpected error occurred: invalid JSON" in result.output