This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 29e2540105 fix(workflow-operator): retry other providers on a 401 
instead of aborting the HF fallback (#7242)
29e2540105 is described below

commit 29e254010546b25dbac703ef59e2f1a2546772f4
Author: Prateek Ganigi <[email protected]>
AuthorDate: Mon Aug 3 16:33:33 2026 -0700

    fix(workflow-operator): retry other providers on a 401 instead of aborting 
the HF fallback (#7242)
    
    ### What changes were proposed in this PR?
    
    In the HuggingFace operator's `_post_with_fallback`, a 401 from any
    single provider immediately aborted the whole fallback chain (reported
    as "Invalid HF API token"), even when another provider would have served
    the model with the same token, one provider can 401 (e.g. missing
    provider-specific permission) while others accept the token.
    
    This removes the 401 short-circuit and adds 401 to the `RETRYABLE` set,
    so the loop tries the remaining providers. "Invalid HF API token" is now
    surfaced only when the final provider still returns 401 (i.e. every
    provider rejected the token).
    
    ### Any related issues, documentation, discussions?
    
    Closes #7194.
    
    ### How was this PR tested?
    
    `sbt "WorkflowOperator/testOnly
    org.apache.texera.amber.operator.huggingFace.*
    org.apache.texera.amber.util.PythonCodeRawInvalidTextSpec"`: passes (125
    tests). Added a test asserting 401 is retryable and the old
    short-circuit is gone; `PythonCodeRawInvalidTextSpec` py-compiles the
    generated Python. scalafmt clean.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    No, this PR was not authored or co-authored using generative AI tooling.
---
 .../operator/huggingFace/codegen/HuggingFaceCodegenBase.scala     | 4 +---
 .../operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala     | 8 ++++++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git 
a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/codegen/HuggingFaceCodegenBase.scala
 
b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/codegen/HuggingFaceCodegenBase.scala
index 77bf488d6c..a4dfc7ca3f 100644
--- 
a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/codegen/HuggingFaceCodegenBase.scala
+++ 
b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/codegen/HuggingFaceCodegenBase.scala
@@ -195,7 +195,7 @@ object HuggingFaceCodegenBase {
        |        Returns (response, provider_summary). provider_summary is None 
on
        |        success or a string describing what failed.
        |        '''
-       |        RETRYABLE = (400, 404, 422, 429, 502, 503)
+       |        RETRYABLE = (400, 401, 404, 422, 429, 502, 503)
        |        last_resp = None
        |        errors = []
        |        for prov in providers:
@@ -247,8 +247,6 @@ object HuggingFaceCodegenBase {
        |                continue
        |            if resp.status_code in (200, 201):
        |                return resp, None
-       |            if resp.status_code == 401:
-       |                return resp, None
        |            try:
        |                detail = resp.json().get("error", resp.text[:200])
        |            except Exception:
diff --git 
a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
 
b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
index 99eb14ed6f..85e38c08e2 100644
--- 
a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
+++ 
b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceInferenceOpDescSpec.scala
@@ -649,6 +649,14 @@ class HuggingFaceInferenceOpDescSpec extends AnyFlatSpec 
with Matchers {
     outSchema.getAttributeNames.contains("hf_response") shouldBe true
   }
 
+  it should "treat a 401 as retryable so one provider's auth failure doesn't 
abort the fallback" in {
+    val code = makeDesc().generatePythonCode()
+    // 401 is in the retryable set -> the loop tries the next provider instead 
of bailing.
+    code should include("RETRYABLE = (400, 401, 404, 422, 429, 502, 503)")
+    // The old short-circuit (return immediately on the first 401) must be 
gone.
+    code should not include ("            if resp.status_code == 401:\n        
        return resp, None")
+  }
+
   it should "mask the API token field as a password widget in the generated 
schema" in {
     val tokenProp = OperatorMetadataGenerator
       .generateOperatorJsonSchema(classOf[HuggingFaceInferenceOpDesc])

Reply via email to