Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
A 3D glowing data cube representing the PlatformCache immutable parameter within the Salesforce apex environment.
Apex

PlatformCache Immutable Parameter: Why It Fails

Cross-namespace PUT errors in PlatformCache trace back to a known platform bug. Here is why the immutable parameter fails and how to write around it in Apex.

Key takeaways The immutable parameter in PlatformCache is currently broken for cross-namespace operations, and throws a Cross-namespace PUT exception whichever boolean you provide. Skip the overloaded put signature that carries the immutable argument altogether. Keep cache entries inside your own namespace. If you have to share data, bridge it with a platform event or a custom setting or object rather than Platform Cache. Wrap every part.put() call in a try-catch so a cache failure cannot break your whole application logic, and your end users still get a working fallback.

The PlatformCache paradox

If you build modular solutions or managed packages, you have probably run into the PlatformCache namespace limits. The strangest one shows up when you call put on Cache.Org or Cache.Session. The immutable parameter, which is supposed to let us control whether cached data can be modified, behaves in ways the documentation does not describe. It fails for a documented platform reason, and the way around it is to stop calling that overload.

The anatomy of the bug

Working inside a namespace, developers set the immutable flag to false so the data can still be updated. The signature part.put(key, value, ttl, visibility, immutable) reads like a promise: pass false as the final argument and the platform keeps that cached value mutable.

In current Salesforce versions you get a persistent runtime error instead:

// Attempting to use the immutable parameter
Cache.SessionPartition part = Cache.Session.getPartition('local.MyPartition');
try {
    part.put('configKey', 'someValue', 3600, Cache.Visibility.ALL, false);
} catch (Cache.Org.OrgCacheException e) {
    // Result: Failed Cache.Session.put() for key 'configKey': Cross-namespace PUT not supported
    System.debug('Error: ' + e.getMessage());
}

Your logic is fine. The Salesforce engineering team has recognized the behavior as a bug (Known Issue a02Ka00000mmTqd). Set immutable to false and the platform still reads the call as an attempt to perform a cross-namespace PUT, which it restricts for security and multi-tenancy isolation.

Why 'immutable' fails

The immutable parameter was meant to prevent race conditions and unauthorized modification of cached objects. Setting the flag creates a read-only contract for that one cache entry.

The conflict sits between namespace boundaries and the storage engine underneath Platform Cache. When a package tries to modify a value in a partition the platform views as owned by a different scope, it throws a security exception. The value you passed for immutable never gets read, because the restriction on cross-namespace writing is evaluated before the mutation policy is applied.

Practical workarounds and best practices

This is a live platform bug, so immutable will not get you out of a cross-namespace storage problem. Architect your caching strategy to be namespace-agnostic or strictly self-contained instead.

1. Avoid cross-namespace dependency

If your soql-in-loops-security-review-impact-for-managed-packages/" class="auto-link">managed package needs to cache data, define the partition inside your own namespace, or use a common namespace your organization controls. Do not write to partitions defined in other packages.

2. Implement a 'get-or-compute' pattern

Rather than forcing an update onto an existing cache key that might belong to another scope, use a get-or-compute pattern that handles a cache miss gracefully.

public static Object getCachedData(String key) {
    Cache.SessionPartition part = Cache.Session.getPartition('local.MyPartition');
    Object cachedValue = part.get(key);
    
    if (cachedValue == null) {
        // Compute the data if not in cache
        cachedValue = performComplexCalculation();
        try {
            // Use the default immutable parameter (true) to avoid the bug
            part.put(key, cachedValue, 3600);
        } catch (Exception e) {
            // Fallback for cache failure
            return cachedValue;
        }
    }
    return cachedValue;
}

3. Use default method signatures

Stay off the put overload that takes the immutable parameter. The overloads that do not expose the flag skip the logic that leads to the Cross-namespace PUT error.

Troubleshooting checklist

  • Check whether the partition you are calling lives in your package's namespace or in the local namespace.
  • Use Cache.Visibility.ALL only when you strictly need it. Cache.Visibility.NAMESPACE tightens security and avoids cross-scope collisions.
  • Check the Salesforce Known Issues site now and then for movement on the ticket linked in the research section.
Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment