Home / Databricks on Azure

Databricks on AzureTroubleshootingAdvanced

Azure Databricks standard access mode errors: RDD, SparkContext, UDF and Spark config failures

Code that ran on a dedicated or no-isolation cluster fails on standard access mode. Map each error to its cause, rewrite RDD and SparkContext code, fix allowlists and restricted configs, or move the job to dedicated compute.

Deepak Bhardwaj7 min read

Applies toAzure Databricks classic compute in standard (formerly shared) access mode, Unity Catalog, Databricks Runtime 13.3 LTS and above, Databricks CLI 0.205+

Symptoms

A notebook or job that worked on a dedicated (single user) or legacy no-isolation cluster fails after it moves to a cluster in standard access mode, often during a Unity Catalog migration or after a cluster policy change. Typical errors:

  • [UNSUPPORTED_CONNECT_FEATURE.RDD] Feature is not supported in Spark Connect: Resilient Distributed Datasets (RDDs) are not available on Standard access mode or Serverless compute.
  • [UNSUPPORTED_CONNECT_FEATURE.SESSION_SPARK_CONTEXT] ... SparkContext is not available on Standard access mode or Serverless compute.
  • Cluster create or edit fails because a Spark config is restricted.
  • Init scripts or JAR/Maven libraries are rejected because they are not on the allowlist.
  • Code that calls the Azure instance metadata service (IMDS) to get a managed identity token hangs or is refused.

Standard access mode runs user code through Spark Connect as a low-privilege user so several users can share one cluster under Unity Catalog. Anything that reaches into the JVM, the driver's SparkContext or the host is blocked by design. The fix is either to rewrite the code to the DataFrame API or to run that workload on dedicated compute.

1. Confirm the access mode and runtime

The exact limits depend on the Databricks Runtime version, so get both values first.

databricks clusters get 0123-456789-abcdefgh --output json \
  | jq '{name: .cluster_name, mode: .data_security_mode, dbr: .spark_version}'

USER_ISOLATION (or DATA_SECURITY_MODE_STANDARD) is standard access mode. SINGLE_USER (or DATA_SECURITY_MODE_DEDICATED) is dedicated. Names vary by API version; check your CLI's output.

To find every active cluster in standard mode across the workspace, use the compute system table:

SELECT cluster_id, cluster_name, owned_by, data_security_mode, dbr_version
FROM system.compute.clusters
WHERE delete_time IS NULL
QUALIFY ROW_NUMBER() OVER (PARTITION BY cluster_id ORDER BY change_time DESC) = 1
ORDER BY data_security_mode, cluster_name;

2. Map the error to the cause

Error or behaviour Cause Fix
UNSUPPORTED_CONNECT_FEATURE.RDD df.rdd, rdd.map, sc.parallelize, sc.textFile Rewrite to DataFrame API (section 3)
UNSUPPORTED_CONNECT_FEATURE.SESSION_SPARK_CONTEXT spark.sparkContext, sc.getConf, sc.setJobGroup, sc.setLocalProperty Use spark.conf, remove JVM-level calls
Hive UDF or CREATE TEMPORARY FUNCTION ... USING JAR fails Hive UDFs are not supported Recreate as a Unity Catalog function
Cluster create/edit fails on a Spark config Restricted config, e.g. spark.jars.packages, spark.driver.extraJavaOptions, spark.executorEnv.* (enforced from DBR 19) Install as a compute library; move env vars to secrets
Init script or JAR/Maven library rejected Not on the Unity Catalog artifact allowlist Add a prefix to the allowlist (section 4)
Spark-submit task won't run Not supported on standard mode Convert to a JAR task
IMDS or WireServer calls time out Host metadata endpoints are blocked Use a Unity Catalog service credential or a secret scope
dbutils.fs can't read an abfss:// path DBUtils only reads cloud storage through an external location Create an external location and grant READ FILES
ML runtime, GPU or R notebooks not available Not supported on standard mode Dedicated compute

Older runtimes have more gaps. For example, Python scalar and pandas UDFs need 13.3 LTS, applyInPandas and mapInPandas need 14.3 LTS, and Spark ML needs 17.0. If the code is valid but still fails, check the runtime-dependent table on the "Standard compute requirements and limitations" page for your version before rewriting anything.

3. Rewrite the common patterns

Most failures come from a short list of RDD and SparkContext calls. These replacements work on standard, dedicated and serverless compute, so the code becomes portable.

Building small DataFrames

# Before: sc.parallelize([(1, "a"), (2, "b")]).toDF(["id", "val"])
df = spark.createDataFrame([(1, "a"), (2, "b")], "id INT, val STRING")

Rows passed to spark.createDataFrame from local data must stay under 128 MB each.

Reading raw files

# Before: sc.textFile("abfss://raw@stacct.dfs.core.windows.net/logs/")
lines = spark.read.text("/Volumes/main/raw/logs/")

# Before: sc.wholeTextFiles(path)
files = spark.read.format("binaryFile").load("/Volumes/main/raw/docs/")

Replace input_file_name() with the _metadata column:

from pyspark.sql import functions as F
df = spark.read.json("/Volumes/main/raw/events/").select("*", F.col("_metadata.file_path").alias("src_file"))

Row-level logic that used rdd.map

# Before: df.rdd.map(lambda r: (r.id, parse(r.payload))).toDF()
from pyspark.sql.types import StringType

@F.udf(StringType())
def parse_udf(payload):
    return parse(payload)

out = df.withColumn("parsed", parse_udf("payload"))

For batch-oriented logic, mapInPandas is usually faster than a row UDF on DBR 14.3 LTS and above.

Configuration and logging

# Before: spark.sparkContext.getConf().get("spark.sql.shuffle.partitions")
spark.conf.get("spark.sql.shuffle.partitions")

# Before: spark.sparkContext.setLogLevel("WARN")  -> remove; use Python logging
import logging
logging.getLogger("myjob").setLevel(logging.WARNING)

sc.broadcast variables have no direct equivalent. For joins, use a broadcast hint: big.join(F.broadcast(small), "key").

Hive UDFs to Unity Catalog functions

CREATE OR REPLACE FUNCTION main.ops.normalize_sku(sku STRING)
RETURNS STRING
LANGUAGE PYTHON
AS $$
  return sku.strip().upper() if sku else None
$$;

GRANT EXECUTE ON FUNCTION main.ops.normalize_sku TO `data-engineers`;

Caution

Python foreachBatch on standard access mode does not support ThreadPoolExecutor or other multi-threaded execution inside the function. Databricks warns this can produce data corruption or inconsistent results without an error. Remove threading from foreachBatch before moving a stream to standard mode.

4. Allowlist init scripts and JAR/Maven libraries

On standard access mode, init scripts and JAR or Maven libraries must match the Unity Catalog artifact allowlist. A metastore admin, or a user with MANAGE_ALLOWLIST, maintains it.

databricks artifact-allowlists get INIT_SCRIPT
databricks artifact-allowlists get LIBRARY_MAVEN

Warning

update replaces the entire list for that artifact type. Export the current list first and merge your new entry, or you will break every other cluster that depended on the old entries.

databricks artifact-allowlists get LIBRARY_MAVEN --output json > maven-allowlist.json
# edit the file: keep existing artifact_matchers, append the new one
databricks artifact-allowlists update LIBRARY_MAVEN --json @maven-allowlist.json

Example entry for an init script folder in a volume:

{"artifact_matchers": [{"artifact": "/Volumes/ops/platform/init-scripts/", "match_type": "PREFIX_MATCH"}]}

Allowlist a narrow prefix (a specific volume folder or Maven group), not a whole catalog or a broad path.

5. When to stop rewriting and use dedicated compute

Standard mode is the recommended default for classic compute, but some workloads belong on dedicated compute:

Workload Recommendation
Heavy RDD code, GraphFrames, libraries that need the JVM or SparkContext Dedicated
Databricks Runtime for ML, GPU training Dedicated
R notebooks Dedicated
Spark-submit tasks you can't convert Dedicated, or convert to JAR task
DataFrame/SQL ETL, BI queries, shared team notebooks Standard (or serverless)

A dedicated cluster can be assigned to a group rather than a single user, so a team can share it. For scheduled jobs, use job compute in dedicated mode with the job's service principal as the run-as identity.

Prevent it next time

  • Test notebooks on standard access mode or serverless before a migration, not after the cluster policy changes.
  • Add a lint rule in CI that flags .rdd, sparkContext, sc. and setLogLevel in new code.
  • Keep the artifact allowlist in source control and apply it with Terraform or the CLI from a merged file, so update never drops entries.
  • Pin each job's runtime and record which runtime-dependent features it uses, then check the limitations page when you upgrade.
  • Run the system table query from section 1 monthly and review clusters still on legacy no-isolation mode.