HumanSignal/label-studio · error · ValueError
Task is required to resolve URI={uri}
Error message
Task is required to resolve URI={uri} What it means
When resolving storage URIs into servable URLs, the storage needs a Task to build the per-task proxy URL (via the task-storage-data-resolve route). resolve_uri raises this ValueError when can_resolve_url matched the URI but the task argument is None, because the proxy link cannot be constructed without a task id.
Source
Thrown at label_studio/io_storages/base_models.py:419
elif isinstance(uri, dict):
resolved = {}
for key in uri.keys():
result = self.resolve_uri(uri[key], task)
resolved[key] = result if result else uri[key]
return resolved
# string: process one url
elif isinstance(uri, str) and self.url_scheme in uri:
try:
# extract uri first from task data
extracted_uri, _ = get_uri_via_regex(uri, prefixes=(self.url_scheme,))
if not self.can_resolve_url(extracted_uri):
logger.debug(f'No storage info found for URI={uri}')
return
if task is None:
logger.error(f'Task is required to resolve URI={uri}', exc_info=True)
raise ValueError(f'Task is required to resolve URI={uri}')
proxy_url = urljoin(
settings.HOSTNAME,
reverse('storages:task-storage-data-resolve', kwargs={'task_id': task.id})
+ f'?fileuri={base64.urlsafe_b64encode(extracted_uri.encode()).decode()}',
)
return uri.replace(extracted_uri, proxy_url)
except Exception:
logger.info(f"Can't resolve URI={uri}", exc_info=True)
def resolve_uris(self, data, task):
"""Resolve all cloud storage URIs in data, replacing each with a proxy URL.
Unlike resolve_uri which only handles the first URI in a string,
this finds and replaces every URI matching this storage's scheme.
Handles str, list, and dict data recursively.
Returns the resolved data, or None if nothing was resolved.View on GitHub (pinned to 0b49e9b539)
Solutions
- Pass the Task instance that owns the data (task.id is used to build the proxy URL).
- Only call resolve_uri when you actually have a task context; otherwise skip resolution for that URI.
- If building tooling, fetch the task first (Task.objects.get) or resolve the file directly via the storage's HTTP URL generator instead.
Example fix
// before
uri = storage.resolve_uri('s3://bucket/file.jpg', task=None)
// after
task = Task.objects.get(id=task_id)
uri = storage.resolve_uri('s3://bucket/file.jpg', task=task) Defensive patterns
Strategy: validation
Validate before calling
if task is None:
raise ValueError('resolve_uri requires a Task instance to build the proxy URL')
uri_to_resolve = uri
if not storage.can_resolve_url(uri_to_resolve):
return # nothing to resolve Type guard
def has_task(task) -> bool:
return task is not None and getattr(task, 'id', None) is not None Try / catch
try:
url = storage.resolve_uri(uri, task=task)
except ValueError as e:
if 'Task is required' in str(e):
url = None # resolution requires task context; skip or handle manually
else:
raise Prevention
- Always thread the Task instance through URI-resolution helpers.
- Skip URI resolution entirely when operating outside a task context.
- Assert task.id exists before calling resolve_uri (unsaved tasks have no id).
When it happens
Trigger: Calling resolve_uri(uri, task=None) (or a caller propagating a missing task) for a URI whose scheme matches the storage's url_scheme and passes can_resolve_url.
Common situations: Resolving URIs outside of a task context (e.g. in import previews or export tooling) where no Task instance exists; passing task=None by default in wrapper utilities.
Related errors
- Task is required to resolve URIs in data={data}
- You do not have permission to create storages for this proje
- Failed to list storage files
- "form_layout.yml" is not found for {self.__class__.__name__}
- Azure account name and key must be set using environment var
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/f022ad6a947e0b46.
Report an issue: GitHub.