evalstate HF Staff commited on
Commit
291b76a
·
verified ·
1 Parent(s): 9729494

Explain OAuth bucket write failures safely

Browse files

Source commit: c290d348b11f29b480df28112b4c7558cc0fad1f

Files changed (2) hide show
  1. Dockerfile +2 -1
  2. research/research_workspace.py +37 -6
Dockerfile CHANGED
@@ -9,7 +9,8 @@ RUN uv pip install --system --no-cache \
9
  fast-agent-mcp==0.9.27 \
10
  'fastmcp[apps]==3.4.4' \
11
  prefab-ui==0.20.2 \
12
- huggingface_hub \
 
13
  pillow
14
 
15
  COPY --link ./ /app
 
9
  fast-agent-mcp==0.9.27 \
10
  'fastmcp[apps]==3.4.4' \
11
  prefab-ui==0.20.2 \
12
+ huggingface_hub==1.24.0 \
13
+ hf-xet==1.5.2 \
14
  pillow
15
 
16
  COPY --link ./ /app
research/research_workspace.py CHANGED
@@ -6,20 +6,40 @@ import hashlib
6
  import json
7
  import os
8
  import re
 
9
  from contextvars import ContextVar
10
  from dataclasses import dataclass
11
  from datetime import UTC, datetime
12
- from typing import Any, Mapping
13
  from uuid import uuid4
14
 
 
 
15
  from huggingface_hub import HfApi, get_token
16
  from huggingface_hub.errors import BucketNotFoundError
17
 
18
- from fast_agent import AgentAuth
19
- from fast_agent.mcp.server.common import normalize_serve_oauth_provider
20
 
21
 
22
- _SAFE_SEGMENT = re.compile(r"[^A-Za-z0-9._-]+")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
 
25
  @dataclass(frozen=True, slots=True)
@@ -104,8 +124,11 @@ def ensure_workspace(
104
  token=token,
105
  )
106
  except Exception as exc:
107
- raise RuntimeError(
108
- f"Bucket {bucket_id!r} is accessible but marker write failed: {exc}"
 
 
 
109
  ) from exc
110
  marker_paths = (
111
  f"{root}scratch/.workspace.json",
@@ -125,6 +148,14 @@ def ensure_workspace(
125
  )
126
 
127
 
 
 
 
 
 
 
 
 
128
  def _token(auth: AgentAuth | None) -> str | None:
129
  if auth is not None and auth.token:
130
  return auth.token
 
6
  import json
7
  import os
8
  import re
9
+ from collections.abc import Mapping
10
  from contextvars import ContextVar
11
  from dataclasses import dataclass
12
  from datetime import UTC, datetime
13
+ from typing import Any
14
  from uuid import uuid4
15
 
16
+ from fast_agent import AgentAuth
17
+ from fast_agent.mcp.server.common import normalize_serve_oauth_provider
18
  from huggingface_hub import HfApi, get_token
19
  from huggingface_hub.errors import BucketNotFoundError
20
 
21
+ _SAFE_SEGMENT = re.compile(r"[^A-Za-z0-9._-]+")
 
22
 
23
 
24
+ class WorkspaceProvisionError(RuntimeError):
25
+ """Safe, user-facing workspace setup failure."""
26
+
27
+ code = "HF_WORKSPACE_PROVISION_FAILED"
28
+
29
+
30
+ class WorkspaceWriteAuthorizationError(WorkspaceProvisionError):
31
+ """The caller can read the workspace bucket but cannot write to it."""
32
+
33
+ code = "HF_BUCKET_WRITE_NOT_AUTHORIZED"
34
+
35
+ def __init__(self) -> None:
36
+ super().__init__(
37
+ "Your Hugging Face connection can read the existing research workspace "
38
+ "but is not authorized to write to it. The `contribute-repos` permission "
39
+ "alone covers only Buckets created by the same OAuth app. Reconnect after "
40
+ "this app's requested write access is available, or use a new workspace "
41
+ "created by this app."
42
+ )
43
 
44
 
45
  @dataclass(frozen=True, slots=True)
 
124
  token=token,
125
  )
126
  except Exception as exc:
127
+ if _is_xet_write_forbidden(exc):
128
+ raise WorkspaceWriteAuthorizationError from exc
129
+ raise WorkspaceProvisionError(
130
+ "The research workspace could not be initialized. Reconnect your "
131
+ "Hugging Face account and try again."
132
  ) from exc
133
  marker_paths = (
134
  f"{root}scratch/.workspace.json",
 
148
  )
149
 
150
 
151
+ def _is_xet_write_forbidden(exc: BaseException) -> bool:
152
+ """Classify hf-xet 1.5.x's opaque write-token authorization failure."""
153
+ if not isinstance(exc, ConnectionError):
154
+ return False
155
+ detail = str(exc)
156
+ return "403 Forbidden" in detail and "/xet-write-token" in detail
157
+
158
+
159
  def _token(auth: AgentAuth | None) -> str | None:
160
  if auth is not None and auth.token:
161
  return auth.token