{"record":{"id":"845176866f3819b6","repo":"crewAIInc/crewAI","slug":"failed-to-publish-tool-local-changes-need-to-be-r","errorCode":null,"errorMessage":"Failed to publish tool.\nLocal changes need to be resolved before publishing. Please do the following:\n* Commit your changes.\n* Push to sync with the remote.\n* Pull the latest changes from the remote.\n\nOnce your repository is up-to-date, retry publishing the tool.","messagePattern":"Failed to publish tool\\.\nLocal changes need to be resolved before publishing\\. Please do the following:\n\\* Commit your changes\\.\n\\* Push to sync with the remote\\.\n\\* Pull the latest changes from the remote\\.\n\nOnce your repository is up-to-date, retry publishing the tool\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"warning","filePath":"lib/cli/src/crewai_cli/tools/main.py","lineNumber":115,"sourceCode":"            self.login()\n            subprocess.run([\"git\", \"init\"], check=True)  # noqa: S607\n            console.print(\n                f\"[green]Created custom tool [bold]{folder_name}[/bold]. Run [bold]cd {project_root}[/bold] to start working.[/green]\"\n            )\n        finally:\n            os.chdir(old_directory)\n\n    def publish(self, is_public: bool, force: bool = False) -> None:\n        if not git.Repository().is_synced() and not force:\n            console.print(\n                \"[bold red]Failed to publish tool.[/bold red]\\n\"\n                \"Local changes need to be resolved before publishing. Please do the following:\\n\"\n                \"* [bold]Commit[/bold] your changes.\\n\"\n                \"* [bold]Push[/bold] to sync with the remote.\\n\"\n                \"* [bold]Pull[/bold] the latest changes from the remote.\\n\"\n                \"\\nOnce your repository is up-to-date, retry publishing the tool.\"\n            )\n            raise SystemExit()\n\n        project_name = get_project_name(require=True)\n        assert isinstance(project_name, str)  # noqa: S101\n\n        project_version = get_project_version(require=True)\n        assert isinstance(project_version, str)  # noqa: S101\n\n        project_description = get_project_description(require=False)\n        encoded_tarball = None\n\n        console.print(\"[bold blue]Discovering tools from your project...[/bold blue]\")\n        project_utils = _require_project_utils()\n        available_exports = project_utils.extract_available_exports()\n\n        if available_exports:\n            console.print(\n                f\"[green]Found these tools to publish: {', '.join([e['name'] for e in available_exports])}[/green]\"\n            )","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/cli/src/crewai_cli/tools/main.py#L97-L133","documentation":"Raised (SystemExit with no code, i.e. exit 0) by ToolCommand.publish() in crewai_cli/tools/main.py when git.Repository().is_synced() returns False and --force was not passed. Publishing packages the current project as a tool; the CLI requires a clean, committed, pushed and up-to-date git state so the published artifact is traceable to a commit.","triggerScenarios":"Running `crewai tool publish` with uncommitted changes, commits not pushed to the remote, local branch behind the remote (unpulled changes), or no remote configured — and without the --force flag.","commonSituations":"Developer edits pyproject.toml or tool code and publishes without committing; CI publish job running on a checkout that never pushes; detached HEAD or freshly cloned repo that is ahead of origin.","solutions":["Commit all local changes: `git add -A && git commit -m \"...\"`.","Push and synchronize: `git push` then `git pull` so is_synced() passes.","If the repo state is intentionally dirty (e.g. CI), pass --force: `crewai tool publish --force`.","Ensure a remote origin is configured (`git remote -v`) — no remote means never synced."],"exampleFix":"# before\ncrewai tool publish --public  # uncommitted changes -> SystemExit\n\n# after\ngit add -A && git commit -m \"chore: publish tool v0.1.1\" && git push\ngit pull\ngrewai tool publish --public  # typo guard: crewai tool publish --public","handlingStrategy":"validation","validationCode":"import subprocess\ndef git_is_synced() -> bool:\n    def clean(cmd):\n        return subprocess.run(cmd, capture_output=True, text=True).stdout.strip() == \"\"\n    return (\n        clean([\"git\", \"status\", \"--porcelain\"])\n        and clean([\"git\", \"log\", \"@{u}..\", \"--oneline\"])\n        and clean([\"git\", \"log\", \"..@{u}\", \"--oneline\"])\n    )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Commit and push before every `crewai tool publish`","Wire publish jobs after a sync step in CI so the checkout is clean and up to date","Reserve --force for pipelines where dirty state is guaranteed and understood"],"tags":["crewai","cli","publish","git","validation"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}