zylon-ai/private-gpt · error · ValueError

Schema must be a dictionary representing JSON Schema

Error message

Schema must be a dictionary representing JSON Schema

What it means

Raised by DELETE /skills/{skill_id}/versions/{version} when the parent skill does not exist in the collection. The route checks the skill first; a miss returns 404 before attempting to delete the version.

Source

Thrown at private_gpt/chat/schema_models.py:87

        """Handle reserved BaseModel attributes - conflicts with Pydantic internals."""
        if field_name.lower() in RESERVED_NAMES:
            return f"{field_name}_field"
        return field_name

    # Apply all sanitization steps in order
    sanitized = _handle_empty_field_name(field_name)
    sanitized = _handle_leading_underscores(sanitized)
    sanitized = _handle_dunder_names(sanitized)
    sanitized = _handle_python_keywords(sanitized)
    sanitized = _handle_reserved_basemodel_attributes(sanitized)

    return sanitized


def _validate_json_schema_item(schema: dict[str, Any], strict: bool = True) -> None:
    """Validate that the schema is a valid JSON Schema object."""
    if not isinstance(schema, dict):
        raise ValueError("Schema must be a dictionary representing JSON Schema")

    if schema == {}:
        return

    # Handle combinators first
    if "oneOf" in schema:
        if not isinstance(schema["oneOf"], list):
            raise ValueError("'oneOf' must be an array of schemas")
        for sub_schema in schema["oneOf"]:
            _validate_json_schema_item(sub_schema, strict=False)
        return  # oneOf schemas don't need type field

    if "anyOf" in schema:
        if not isinstance(schema["anyOf"], list):
            raise ValueError("'anyOf' must be an array of schemas")
        for sub_schema in schema["anyOf"]:
            _validate_json_schema_item(sub_schema, strict=False)
        return  # anyOf schemas don't need type field

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Treat as success if the skill itself is gone — the version is gone with it.
  2. Refresh the version list after any skill-level delete and drop stale rows.
  3. Confirm collection matches before issuing the delete.

Example fix

// before
await skillsApi.deleteVersion(id, token, col);

// after
try { await skillsApi.deleteVersion(id, token, col); }
catch (e) {
  const skill = await skillsApi.get(id, col).catch(() => null);
  if (e.status !== 404 || skill) throw e; // 404 + no skill = nothing to do
}
Defensive patterns

Strategy: try-catch

Validate before calling

const skill = await skillsApi.get(id, collection).catch(() => null);
if (!skill) return { deleted: true, viaSkillDeletion: true }; // nothing left

Try / catch

try { await skillsApi.deleteVersion(id, token, collection); }
catch (e) {
  const skill = await skillsApi.get(id, collection).catch(() => null);
  if (e.status === 404 && !skill) return; // skill gone -> version gone
  throw e;
}

Prevention

When it happens

Trigger: Deleting a version of a skill that was deleted (whole-skill deletion removes versions); wrong collection parameter; duplicate delete.

Common situations: Deleting the entire skill in one session while another session deletes an individual version; stale version list after skill removal.

Related errors


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