unslothai/unsloth · error · ValueError

Linked folders support only knowledge-base and project scope

Error message

Linked folders support only knowledge-base and project scopes

What it means

create_folder() only accepts scope_type in {"knowledge_base", "project"}; any other scope string raises immediately. Linked folders are partitioned per KB or per project because those are the only scopes with rows in the linked_folders table (scope column) and retirement tracking (linked_folder_retired_scopes).

Source

Thrown at studio/backend/core/rag/folder_sync.py:225

                for encoded, decoded in escaped.items():
                    path = path.replace(encoded, decoded)
                points.add(_path_key(os.path.realpath(path)))
    except OSError:
        return frozenset()
    return frozenset(points)


def create_folder(
    *,
    scope_type: str,
    scope_id: str,
    path: str,
    expected_identity: tuple[int, int] | None = None,
    name: str | None = None,
    auto_sync: bool = True,
) -> dict:
    if scope_type not in {"knowledge_base", "project"}:
        raise ValueError("Linked folders support only knowledge-base and project scopes")
    normalized = validate_folder_path(path)
    try:
        root_device, root_inode = _root_identity(normalized)
    except RuntimeError as exc:
        raise ValueError(str(exc)) from exc
    if expected_identity is not None and (root_device, root_inode) != expected_identity:
        raise ValueError("Linked folder changed after it was selected")
    scope = (
        store.kb_scope(scope_id)
        if scope_type == "knowledge_base"
        else store.project_scope(scope_id)
    )
    folder_id = str(uuid.uuid4())
    now = _now()
    with _scope_lock(scope):
        conn = rag_db.get_connection()
        try:
            conn.execute("BEGIN IMMEDIATE")

View on GitHub (pinned to 203007d190)

Solutions

  1. Pass scope_type exactly 'knowledge_base' or 'project' and use store.kb_scope(scope_id)/store.project_scope(scope_id) accordingly.
  2. Whitelist the scope in the API layer before calling create_folder so invalid values never reach the sync module.
  3. If a new scope type is genuinely needed, extend the set in both create_folder and create_folder_with_sync plus scope resolution and retirement handling.

Example fix

# before
create_folder(scope_type=scope, scope_id=sid, path=p)  # scope may be 'user'

# after
if scope not in {"knowledge_base", "project"}:
    raise HTTPException(400, "unsupported scope")
create_folder(scope_type=scope, scope_id=sid, path=p)
Defensive patterns

Strategy: validation

Validate before calling

_LINKABLE_SCOPES = {"knowledge_base", "project"}

def is_linkable_scope(scope_type: str) -> bool:
    return scope_type in _LINKABLE_SCOPES

Type guard

def is_linkable_scope(scope_type: str | None) -> TypeGuard[Literal["knowledge_base", "project"]]:
    return scope_type in ("knowledge_base", "project")

Try / catch

try:
    create_folder(scope_type=scope, ...)
except ValueError as e:
    if "only knowledge-base and project" in str(e):
        return HTTP_422(...)  # client bug, do not retry
    raise

Prevention

When it happens

Trigger: Calling create_folder(scope_type="user"|"organization"|"chat"|None, ...) with any value outside the two allowed strings; also duplicated by create_folder_with_sync (line 341) with the same guard.

Common situations: Frontend sends a new scope kind after an API change; a caller passes the raw scope string from a URL parameter without whitelisting; copy-pasted code from another feature that supports more scopes.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/85c10b9d829f05da. Report an issue: GitHub.