diff --git a/.github/workflows/test-cache.yml b/.github/workflows/test-cache.yml
index 7bff674..96df107 100644
--- a/.github/workflows/test-cache.yml
+++ b/.github/workflows/test-cache.yml
@@ -21,7 +21,7 @@ jobs:
         uses: ./
         with:
           enable-cache: true
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache
       - run: uv sync
         working-directory: __tests__/fixtures/uv-project
   test-restore-cache:
@@ -37,7 +37,7 @@ jobs:
         uses: ./
         with:
           enable-cache: true
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache
       - name: Cache was hit
         run: |
           if [ "$CACHE_HIT" != "true" ]; then
@@ -59,7 +59,7 @@ jobs:
           cache-dependency-glob: |
             __tests__/fixtures/uv-project/uv.lock
             **/pyproject.toml
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-dependency-glob
       - run: uv sync
         working-directory: __tests__/fixtures/uv-project
   test-restore-cache-dependency-glob:
@@ -79,7 +79,8 @@ jobs:
           cache-dependency-glob: |
             __tests__/fixtures/uv-project/uv.lock
             **/pyproject.toml
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-dependency-glob
+          ignore-nothing-to-cache: true
       - name: Cache was not hit
         run: |
           if [ "$CACHE_HIT" == "true" ]; then
@@ -96,7 +97,7 @@ jobs:
         uses: ./
         with:
           enable-cache: true
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-local
           cache-local-path: /tmp/uv-cache
       - run: uv sync
         working-directory: __tests__/fixtures/uv-project
@@ -110,7 +111,7 @@ jobs:
         uses: ./
         with:
           enable-cache: true
-          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}
+          cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-local
           cache-local-path: /tmp/uv-cache
       - name: Cache was hit
         run: |
@@ -122,38 +123,38 @@ jobs:
       - run: uv sync
         working-directory: __tests__/fixtures/uv-project
 
-  prepare-tilde-expansion-tests:
+  test-tilde-expansion-cache-local-path:
     runs-on: selfhosted-ubuntu-arm64
     steps:
+      - uses: actions/checkout@v4
       - name: Create cache directory
         run: mkdir -p ~/uv-cache
         shell: bash
-      - name: Create cache dependency glob file
-        run: touch ~/uv-cache.glob
-        shell: bash
-
-  test-tilde-expansion-cache-local-path:
-    needs: prepare-tilde-expansion-tests
-    runs-on: selfhosted-ubuntu-arm64
-    steps:
-      - uses: actions/checkout@v4
       - name: Setup with cache
         uses: ./
         with:
-          enable-cache: true
           cache-local-path: ~/uv-cache/cache-local-path
+      - run: uv sync
+        working-directory: __tests__/fixtures/uv-project
 
   test-tilde-expansion-cache-dependency-glob:
-    needs: prepare-tilde-expansion-tests
     runs-on: selfhosted-ubuntu-arm64
     steps:
       - uses: actions/checkout@v4
+      - name: Create cache directory
+        run: mkdir -p ~/uv-cache
+        shell: bash
+      - name: Create cache dependency glob file
+        run: touch ~/uv-cache.glob
+        shell: bash
       - name: Setup with cache
         uses: ./
         with:
           enable-cache: true
           cache-local-path: ~/uv-cache/cache-dependency-glob
           cache-dependency-glob: "~/uv-cache.glob"
+      - run: uv sync
+        working-directory: __tests__/fixtures/uv-project
 
   cleanup-tilde-expansion-tests:
     needs:
diff --git a/README.md b/README.md
index fbf26a4..73a1c1b 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,8 @@ Set up your GitHub Actions workflow with a specific version of [uv](https://docs
   - [Enable Caching](#enable-caching)
     - [Cache dependency glob](#cache-dependency-glob)
   - [Local cache path](#local-cache-path)
+  - [Disable cache pruning](#disable-cache-pruning)
+  - [Ignore nothing to cache](#ignore-nothing-to-cache)
   - [GitHub authentication token](#github-authentication-token)
   - [UV_TOOL_DIR](#uv_tool_dir)
   - [UV_TOOL_BIN_DIR](#uv_tool_bin_dir)
@@ -195,6 +197,19 @@ input.
     prune-cache: false
 ```
 
+### Ignore nothing to cache
+
+By default, the action will fail if there is nothing to cache. If you want to ignore this, set the
+`ignore-nothing-to-cache` input to `true`.
+
+```yaml
+- name: Ignore nothing to cache
+  uses: astral-sh/setup-uv@v3
+  with:
+    enable-cache: true
+    ignore-nothing-to-cache: true
+```
+
 ### GitHub authentication token
 
 This action uses the GitHub API to fetch the uv release artifacts. To avoid hitting the GitHub API
diff --git a/action.yml b/action.yml
index bcb05f9..3356c2f 100644
--- a/action.yml
+++ b/action.yml
@@ -31,7 +31,10 @@ inputs:
     default: ""
   prune-cache:
     description: "Prune cache before saving."
-    default: true
+    default: "true"
+  ignore-nothing-to-cache:
+    description: "Ignore when nothing is found to cache."
+    default: "false"
   tool-dir:
     description: "Custom path to set UV_TOOL_DIR to."
     required: false
diff --git a/dist/save-cache/index.js b/dist/save-cache/index.js
index ea6058c..5d58cbf 100644
--- a/dist/save-cache/index.js
+++ b/dist/save-cache/index.js
@@ -82510,6 +82510,7 @@ exports.run = run;
 const cache = __importStar(__nccwpck_require__(5116));
 const core = __importStar(__nccwpck_require__(7484));
 const exec = __importStar(__nccwpck_require__(5236));
+const fs = __importStar(__nccwpck_require__(3024));
 const restore_cache_1 = __nccwpck_require__(5391);
 const inputs_1 = __nccwpck_require__(9612);
 function run() {
@@ -82517,18 +82518,18 @@ function run() {
         try {
             if (inputs_1.enableCache) {
                 yield saveCache();
+                // node will stay alive if any promises are not resolved,
+                // which is a possibility if HTTP requests are dangling
+                // due to retries or timeouts. We know that if we got here
+                // that all promises that we care about have successfully
+                // resolved, so simply exit with success.
+                process.exit(0);
             }
         }
         catch (error) {
             const err = error;
             core.setFailed(err.message);
         }
-        // node will stay alive if any promises are not resolved,
-        // which is a possibility if HTTP requests are dangling
-        // due to retries or timeouts. We know that if we got here
-        // that all promises that we care about have successfully
-        // resolved, so simply exit with success.
-        process.exit(0);
     });
 }
 function saveCache() {
@@ -82547,8 +82548,23 @@ function saveCache() {
             yield pruneCache();
         }
         core.info(`Saving cache path: ${inputs_1.cacheLocalPath}`);
-        yield cache.saveCache([inputs_1.cacheLocalPath], cacheKey);
-        core.info(`cache saved with the key: ${cacheKey}`);
+        if (!fs.existsSync(inputs_1.cacheLocalPath) && !inputs_1.ignoreNothingToCache) {
+            throw new Error(`Cache path ${inputs_1.cacheLocalPath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`);
+        }
+        try {
+            yield cache.saveCache([inputs_1.cacheLocalPath], cacheKey);
+            core.info(`cache saved with the key: ${cacheKey}`);
+        }
+        catch (e) {
+            if (e instanceof Error &&
+                e.message ===
+                    "Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.") {
+                core.info("No cacheable paths were found. Ignoring because ignore-nothing-to-save is enabled.");
+            }
+            else {
+                throw e;
+            }
+        }
     });
 }
 function pruneCache() {
@@ -82598,7 +82614,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.githubToken = exports.toolDir = exports.toolBinDir = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.version = void 0;
+exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.version = void 0;
 const core = __importStar(__nccwpck_require__(7484));
 const node_path_1 = __importDefault(__nccwpck_require__(6760));
 exports.version = core.getInput("version");
@@ -82608,6 +82624,7 @@ exports.cacheSuffix = core.getInput("cache-suffix") || "";
 exports.cacheLocalPath = getCacheLocalPath();
 exports.cacheDependencyGlob = core.getInput("cache-dependency-glob");
 exports.pruneCache = core.getInput("prune-cache") === "true";
+exports.ignoreNothingToCache = core.getInput("ignore-nothing-to-cache") === "true";
 exports.toolBinDir = getToolBinDir();
 exports.toolDir = getToolDir();
 exports.githubToken = core.getInput("github-token");
diff --git a/dist/setup/index.js b/dist/setup/index.js
index a17d5c8..d062c69 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -90268,7 +90268,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.githubToken = exports.toolDir = exports.toolBinDir = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.version = void 0;
+exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.version = void 0;
 const core = __importStar(__nccwpck_require__(7484));
 const node_path_1 = __importDefault(__nccwpck_require__(6760));
 exports.version = core.getInput("version");
@@ -90278,6 +90278,7 @@ exports.cacheSuffix = core.getInput("cache-suffix") || "";
 exports.cacheLocalPath = getCacheLocalPath();
 exports.cacheDependencyGlob = core.getInput("cache-dependency-glob");
 exports.pruneCache = core.getInput("prune-cache") === "true";
+exports.ignoreNothingToCache = core.getInput("ignore-nothing-to-cache") === "true";
 exports.toolBinDir = getToolBinDir();
 exports.toolDir = getToolDir();
 exports.githubToken = core.getInput("github-token");
diff --git a/src/save-cache.ts b/src/save-cache.ts
index cf5acca..bc2bbf2 100644
--- a/src/save-cache.ts
+++ b/src/save-cache.ts
@@ -1,6 +1,7 @@
 import * as cache from "@actions/cache";
 import * as core from "@actions/core";
 import * as exec from "@actions/exec";
+import * as fs from "node:fs";
 import {
   STATE_CACHE_MATCHED_KEY,
   STATE_CACHE_KEY,
@@ -8,6 +9,7 @@ import {
 import {
   cacheLocalPath,
   enableCache,
+  ignoreNothingToCache,
   pruneCache as shouldPruneCache,
 } from "./utils/inputs";
 
@@ -15,17 +17,17 @@ export async function run(): Promise<void> {
   try {
     if (enableCache) {
       await saveCache();
+      // node will stay alive if any promises are not resolved,
+      // which is a possibility if HTTP requests are dangling
+      // due to retries or timeouts. We know that if we got here
+      // that all promises that we care about have successfully
+      // resolved, so simply exit with success.
+      process.exit(0);
     }
   } catch (error) {
     const err = error as Error;
     core.setFailed(err.message);
   }
-  // node will stay alive if any promises are not resolved,
-  // which is a possibility if HTTP requests are dangling
-  // due to retries or timeouts. We know that if we got here
-  // that all promises that we care about have successfully
-  // resolved, so simply exit with success.
-  process.exit(0);
 }
 
 async function saveCache(): Promise<void> {
@@ -46,9 +48,27 @@ async function saveCache(): Promise<void> {
   }
 
   core.info(`Saving cache path: ${cacheLocalPath}`);
-  await cache.saveCache([cacheLocalPath], cacheKey);
-
-  core.info(`cache saved with the key: ${cacheKey}`);
+  if (!fs.existsSync(cacheLocalPath) && !ignoreNothingToCache) {
+    throw new Error(
+      `Cache path ${cacheLocalPath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`,
+    );
+  }
+  try {
+    await cache.saveCache([cacheLocalPath], cacheKey);
+    core.info(`cache saved with the key: ${cacheKey}`);
+  } catch (e) {
+    if (
+      e instanceof Error &&
+      e.message ===
+        "Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved."
+    ) {
+      core.info(
+        "No cacheable paths were found. Ignoring because ignore-nothing-to-save is enabled.",
+      );
+    } else {
+      throw e;
+    }
+  }
 }
 
 async function pruneCache(): Promise<void> {
diff --git a/src/utils/inputs.ts b/src/utils/inputs.ts
index 57af924..d817815 100644
--- a/src/utils/inputs.ts
+++ b/src/utils/inputs.ts
@@ -8,6 +8,8 @@ export const cacheSuffix = core.getInput("cache-suffix") || "";
 export const cacheLocalPath = getCacheLocalPath();
 export const cacheDependencyGlob = core.getInput("cache-dependency-glob");
 export const pruneCache = core.getInput("prune-cache") === "true";
+export const ignoreNothingToCache =
+  core.getInput("ignore-nothing-to-cache") === "true";
 export const toolBinDir = getToolBinDir();
 export const toolDir = getToolDir();
 export const githubToken = core.getInput("github-token");