Skip to content

InternalCompat: Internal Python tests request a Maven coordinate that was never published (HHmm timestamp race) #2653

Closed

Description

Summary

The SynapseML-Internal Compatibility Check job fails on essentially every PR with an opaque JAVA_GATEWAY_EXITED. The underlying cause is a timestamp race in the Internal Maven coordinate: the version string embeds a live HHmm value that is recomputed on each invocation, so the Run Internal Python tests (ExcludeAIFunc) step requests an artifact that was never published.

The job is already continueOnError: true and is not a required status check, so this does not block merges — but it produces a permanently red check run, which trains reviewers to ignore a signal that is supposed to catch real OSS→Internal breakage.

Evidence

Two builds from different PRs, different Scala/Python targets, same failure shape:

PR published to ~/.m2 requested at test time drift
#2645 1.1.3.0-python3.13-5-5474bb77-20260817-**1132**-SNAPSHOT …-5474bb77-20260817-**1136**-SNAPSHOT 4 min
#2646 1.1.3.0-python3.12-0-46cc34d2-20260817-**1240**-SNAPSHOT …-46cc34d2-20260817-**1243**-SNAPSHOT 3 min

Same git SHA, same python tag, same base version — only the HHmm component differs.

Package Internal Python against OSS succeeds and logs the publish:

[info] published ...-internal_2.13 to file:/home/vsts/.m2/repository/com/microsoft/azure/...-internal_2.13/1.1.3.0-python3.13-5-5474bb77-20260817-1132-SNAPSHOT/...

Run Internal Python tests (ExcludeAIFunc) then dies with:

Exception in thread "main" java.lang.RuntimeException: [unresolved dependency:
  com.microsoft.azure#...-internal_2.13;1.1.3.0-python3.13-5-5474bb77-20260817-1136-SNAPSHOT: not found]
	at org.apache.spark.util.MavenUtils$.resolveMavenCoordinates(MavenUtils.scala:539)
	at org.apache.spark.deploy.SparkSubmit.prepareSubmitEnvironment(SparkSubmit.scala:340)

Because spark-submit exits before writing its port, PySpark surfaces only:

pyspark.errors.exceptions.base.PySparkRuntimeError: [JAVA_GATEWAY_EXITED]
  Java gateway process exited before sending its port number

which is why every test in the step reports as an ERROR at fixture setup rather than pointing at the real cause.

Why the existing mitigation is insufficient

pipeline.yaml already documents this failure mode and mitigates half of it:

# packagePython and publishM2 MUST share one sbt session. Internal's version embeds an HHmm timestamp, so separate invocations can differ by a minute: packagePython bakes the jar coordinate into the generated Python package, publishM2 then publishes a *different* version, and the Spark launch inside make_mlflow_models.py fails to resolve it - surfacing only as an opaque JAVA_GATEWAY_EXITED. Observed: packaged 1022, published 1023.

That fix works — in both builds above, packagePython and publishM2 agree (1132 / 1240). The remaining gap is the next step: make_mlflow_models.py runs as a separate process 3–4 minutes later and recomputes the timestamp. Since the publish→test gap is reliably longer than a minute, this now fails almost deterministically rather than intermittently.

Suggested fix

The durable fix belongs in SynapseML-Internal: the Python-side coordinate should read the version baked in at packagePython time rather than recomputing it from the wall clock. Any of these would work:

  1. Have the generated Python package expose the exact coordinate written during packagePython, and have init_spark / session_utils read that constant.
  2. Compute the timestamped version once per build and thread it through as an environment variable that both sbt and the Python fixtures honour.
  3. Drop HHmm from the coordinate entirely for CI builds — the git SHA already makes it unique.

Option 2 could be driven from the OSS pipeline.yaml if Internal accepts a version override; options 1 and 3 are purely Internal-side.

Impact / non-impact

  • Not caused by any particular PR — reproduced on two unrelated PRs, and pipeline.yaml cites build 230974877 hitting it on a PR that changed only pipeline.yaml.
  • Internal Scala tests are unaffected: they resolve through sbt's classpath, never through Maven, and pass in the same builds where the Python step fails.
  • The check is advisory (continueOnError: true) and is not in the required status checks, so merges are not blocked.

Repro

Any PR build of definition 17563. Compare the version in the published ...-internal_... line of Package Internal Python against OSS against the version in the unresolved dependency line of Run Internal Python tests (ExcludeAIFunc).

Activity

  1. added a commit that references this issue on Aug 17, 2026
    7188225
  2. ranadeepsingh commented on Aug 17, 2026

    @ranadeepsingh
    CollaboratorAuthor

    Correction to the root cause above. I originally wrote that make_mlflow_models.py recomputes the version. Reading the SynapseML-Internal source and the per-step ADO timeline shows that is wrong, and the real mechanism is one step later.

    make_mlflow_models.py succeeds. It resolves the packaged jar correctly (found … in local-m2-cache, [SUCCESSFUL] … .jar (3ms)). The coordinate is not recomputed at test time either — it is a baked constant read out of the installed package:

    # src/test/python/setup_spark.py
    from synapse.ml.ebm import __spark_package_version__ as __spark_internal_package_version__

    Corrected timeline, from build 231488245:

    time step version
    11:09 Retarget Internal to this build — two sed -i on build.sbt tree becomes dirty
    11:32 sbt packagePython publishM2 bakes 1132 and publishes that same jar ✅
    11:33–11:36 make_mlflow_models.py resolves 1132 fine ✅
    11:36 sbt testPythonExcludeAIFunc re-runs CodeGen in a new sbt session rebakes + pip-installs 1136
    11:37+ pytest fixtures request 1136 — never published ❌

    1132 and 1136 are literally the sbt-session start times.

    Why this matters practically: it rules out the narrower fix. Pinning only the packaging step could never have worked, because the version is recomputed by a later, different sbt session. The tree has to be clean.

    Fix is up as #2655, targeted at spark4.1 so it is validated where the check actually fails.

  3. ranadeepsingh commented on Aug 17, 2026

    @ranadeepsingh
    CollaboratorAuthor

    Fix validated on the real pipeline. Build 231538523 (PR #2655, targeting spark4.1):

    Run Internal Python tests (ExcludeAIFunc)   succeeded
    ============ 21 passed, 2 skipped, 22 warnings in 759.99s (0:12:39) ============
    

    The ~21 tests that used to error at fixture setup with JAVA_GATEWAY_EXITED now pass.

    The requested coordinate resolves because it no longer moves:

    found com.microsoft.azure#...-internal_2.13;1.1.3.0-python3.13-6-481ff5cd-SNAPSHOT in local-m2-cache
    [SUCCESSFUL ] ...-internal_2.13.jar (5ms)
    

    No timestamp — distance 5 -> 6 from the retarget commit, matching the shape Internal's own CI produces.

    Before/after, same job across recent builds:

    build branch Python step
    231538523 PR #2655 (fix) succeeded
    231528616 PR #2646 failed
    231505494 PR #2630 failed

    Separate pre-existing issue, not covered by this fix: Run Internal Scala tests still fails, so the overall job stays red. It is unrelated — it fails the same way on #2646, which has none of these changes — and it is live-service non-determinism in SynapseML-Internal's own AI Foundry suites, with a different failing set each run:

    build failing tests assertion
    #2646 Summarize Paragraphs, Extract Name and Address (x2) 0 did not equal 2
    #2655 Review Sentiments, Classify Descriptions 3 did not equal 4

    126/128 pass. Those row-count assertions live in OpenAISummarizeSuite / OpenAIExtractSuite / OpenAIAnalyzeSentimentSuite in SynapseML-Internal and should be tracked there.

  4. added a commit that references this issue on Aug 18, 2026
    85285a1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions