HumanSignal/label-studio · error · ValueError

Task is required to resolve URIs in data={data}

Error message

Task is required to resolve URIs in data={data}

What it means

resolve_uris replaces all storage-scheme URIs found in a task data string with proxy URLs; that substitution requires the owning Task. It raises this ValueError when at least one resolvable URI was found (get_all_uris_via_regex matched) but the task argument is None, since each URI needs task.id for the proxy route.

Source

Thrown at label_studio/io_storages/base_models.py:460

        if isinstance(data, list):
            resolved = [self.resolve_uris(item, task) or item for item in data]
            return resolved

        if isinstance(data, dict):
            resolved = {key: self.resolve_uris(val, task) or val for key, val in data.items()}
            return resolved

        if not isinstance(data, str) or self.url_scheme not in data:
            return None

        try:
            all_uris = get_all_uris_via_regex(data, prefixes=[self.url_scheme])
            if not all_uris:
                return None

            if task is None:
                logger.error(f'Task is required to resolve URIs in data={data}', exc_info=True)
                raise ValueError(f'Task is required to resolve URIs in data={data}')

            resolved = data
            any_resolved = False
            for extracted_uri, _ in all_uris:
                if not self.can_resolve_url(extracted_uri):
                    continue
                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()}',
                )
                resolved = resolved.replace(extracted_uri, proxy_url, 1)
                any_resolved = True
            return resolved if any_resolved else None
        except Exception:
            logger.info(f"Can't resolve URIs in data={data}", exc_info=True)
            return None

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Provide the Task instance owning the data when calling resolve_uris.
  2. Skip resolution when no task is available — check can_resolve_url / regex yourself first and only call with a task.
  3. Fetch or pass the task id through your pipeline so resolution happens in task context.

Example fix

// before
resolved = storage.resolve_uris(task_data_json, task=None)

// after
resolved = storage.resolve_uris(task_data_json, task=task)  # task from the annotation/loop context
Defensive patterns

Strategy: validation

Validate before calling

from label_studio.io_storages.functions import get_all_uris_via_regex
all_uris = get_all_uris_via_regex(data, prefixes=[storage.url_scheme])
if all_uris and task is None:
    raise ValueError('Resolving these URIs requires the owning Task')

Type guard

def resolution_possible(data, task, storage) -> bool:
    has_uris = bool(get_all_uris_via_regex(data, prefixes=[storage.url_scheme]))
    return not has_uris or task is not None

Try / catch

try:
    resolved = storage.resolve_uris(data, task=task)
except ValueError as e:
    if 'Task is required' in str(e):
        resolved = data  # leave URIs unresolved when no task context
    else:
        raise

Prevention

When it happens

Trigger: Calling resolve_uris(data, task=None) where data contains at least one URI matching the storage url_scheme prefix and passing can_resolve_url.

Common situations: Bulk URI resolution utilities invoked without task context; export/import flows that pass data strings around without carrying the Task reference.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/e7b483db962359b2. Report an issue: GitHub.