zylon-ai/private-gpt · error · SkillDomainError

MISSING_FILES

MISSING_FILES

Error message

At least one file is required

What it means

SkillDomainError with code MISSING_FILES, thrown by stored_files_from_uploads when the uploads list is empty. The skills upload pipeline requires at least one UploadFile (or one zip containing files) to build a skill version. It is a domain-level guard, not a framework error, and typically surfaces as an HTTP 401-mapped error response.

Source

Thrown at private_gpt/server/skills/skills_files.py:46

            if raw is None:
                continue
            filename, content_type = _infer_file_meta(k, raw)
            uploads.append(
                UploadFile(
                    file=BytesIO(raw),
                    filename=filename,
                    headers=Headers({"content-type": content_type}),
                )
            )
    return uploads


async def stored_files_from_uploads(
    uploads: list[UploadFile],
    default_mime_type: str | None = "application/octet-stream",
) -> list[StoredFile]:
    if not uploads:
        raise SkillDomainError(
            SkillErrorCode.MISSING_FILES, "At least one file is required"
        )

    resolved: dict[str, StoredFile] = {}
    for upload in uploads:
        payload = await upload.read()

        if _is_zip(upload):
            for path, content in _extract_zip(upload, payload):
                normalized = _normalize_path(path)
                resolved[normalized] = StoredFile(
                    path=normalized, content=content, mime_type=None
                )
        else:
            name = _normalize_path(upload.filename or "")
            resolved[name] = StoredFile(
                path=name, content=payload, mime_type=upload.content_type
            )

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Include at least one file part (typically a zip containing SKILL.md) in the multipart request.
  2. If invoking stored_files_from_uploads programmatically, guard with `if not uploads: return []` (or raise your own clearer error) before calling.
  3. Log the raw multipart body in a repro to confirm the file field name matches what the server expects.

Example fix

# before
files = await stored_files_from_uploads([])  # SkillDomainError
# after
if uploads:
    files = await stored_files_from_uploads(uploads)
else:
    raise HTTPException(422, 'Attach at least one file to the upload')
Defensive patterns

Strategy: validation

Validate before calling

const form = new FormData();
// ...
if (![...form.keys()].some((k) => form.getAll(k).some((v) => v instanceof File))) {
  throw new Error('Attach at least one file before submitting');
}

Type guard

const hasFiles = (form: FormData): boolean =>
  Array.from(form.getAll('files')).some((v) => v instanceof File && v.size >= 0);

Prevention

When it happens

Trigger: Calling the multipart upload endpoint with no file parts at all, or a client that sends only form fields; also calling stored_files_from_uploads directly with an empty list (e.g. after filtering out zero-length parts upstream).

Common situations: HTML forms or scripts where the file input is optional and left blank; fetch/axios multipart bodies built from an empty array; test harnesses passing [] accidentally; upstream code dropping files due to size limits before the handler runs.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/451be854c2cb2fd3. Report an issue: GitHub.