> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opensourcemalware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API error responses

> Every non-200 response returned by the OpenSourceMalware APIs.

This page covers all seven API endpoints:

* the five read endpoints:`check-malicious`, `query-latest`, `threat-feed`, `threat-data`, `query-by-username`
* the two write endpoints:`submit-threat-report`, `modify-threat-report`

<Note>
  A `CORS OPTIONS` preflight request returns `204` or `200` — this is expected browser behavior, not an error.
</Note>

## Quick reference

| Status | Meaning                                           | Where it shows up                                                         |
| ------ | ------------------------------------------------- | ------------------------------------------------------------------------- |
| `400`  | Bad request — missing or invalid parameters       | All endpoints (details vary)                                              |
| `401`  | Missing, invalid, or inactive credentials         | All endpoints                                                             |
| `403`  | Account tier or role doesn't meet the requirement | `threat-feed`, `threat-data`, `query-by-username`, `submit-threat-report` |
| `404`  | Resource not found                                | `threat-data`, `modify-threat-report`                                     |
| `405`  | Method not allowed                                | All endpoints                                                             |
| `409`  | Conflict — duplicate record                       | `submit-threat-report` only                                               |
| `429`  | Rate limit or quota exceeded                      | All endpoints                                                             |
| `500`  | Internal server error                             | All endpoints                                                             |

***

## Shared errors — read endpoints

These are returned by every read endpoint (`check-malicious`, `query-latest`, `threat-feed`, `threat-data`, `query-by-username`). Wording and status are identical unless noted per endpoint below.

### 405 — Method not allowed

```json theme={null}
{ "error": "Method not allowed" }
```

<Note>
  `query-by-username` variant: `"Method not allowed. Use GET."`
</Note>

### 429 — IP rate limit (500 req / 15 min per IP)

```json theme={null}
{ "error": "Rate limit exceeded for your IP address. Please try again later." }
```

### 429 — Token rate limit (per-minute, tier-scoped)

```json theme={null}
{ "error": "Rate limit exceeded. Maximum 60 requests per minute (standard tier)." }
```

### 429 — Daily quota exceeded

```json theme={null}
{
  "error": "Daily quota exceeded: 2000/2000 requests in the last 24 hours (free tier). Upgrade to Pro for higher limits.",
  "upgrade_url": "https://opensourcemalware.com/pro-features",
  "tier": "free",
  "used": 2000,
  "limit": 2000
}
```

<Note>
  `threat-feed` and `query-by-username` omit the trailing `"Upgrade to Pro for higher limits."` sentence but keep the same fields.
</Note>

### 500 — Internal server error

```json theme={null}
{ "error": "Internal server error" }
```

***

## check-malicious

### 401 — Missing API token

```json theme={null}
{ "error": "API token required. Provide token in Authorization header or apikey query parameter." }
```

### 401 — Invalid or inactive token

```json theme={null}
{ "error": "Invalid or inactive API token" }
```

### 400 — Invalid or missing `report_type`

```json theme={null}
{ "error": "Invalid or missing 'report_type' parameter. Valid types: <comma-separated list of VALID_TYPES>" }
```

### 400 — Missing `resource_identifier`

```json theme={null}
{ "error": "Missing required 'resource_identifier' parameter." }
```

### 400 — Invalid repository format

```json theme={null}
{ "error": "Invalid repository format. Must include protocol (e.g., 'https://github.com/org/repo' or 'http://gitlab.example.com/org/repo')." }
```

### 500 — Database query failed

```json theme={null}
{ "error": "Database query failed" }
```

***

## query-latest

### 401 — Missing API token

```json theme={null}
{ "error": "API token required. Provide it via Authorization header (Bearer token) or apikey query parameter." }
```

### 401 — Invalid token

```json theme={null}
{ "error": "Invalid API token" }
```

### 401 — Inactive token

```json theme={null}
{ "error": "API token is inactive" }
```

### 400 — Missing `ecosystem`

```json theme={null}
{ "error": "ecosystem parameter is required" }
```

### 500 — Query failed

```json theme={null}
{ "error": "Failed to query threats" }
```

***

## threat-feed

### 401 — Missing API token

```json theme={null}
{ "error": "API token required. Provide it via Authorization header (Bearer token) or apikey query parameter." }
```

### 401 — Invalid token

```json theme={null}
{ "error": "Invalid API token" }
```

### 401 — Inactive token

```json theme={null}
{ "error": "API token is inactive" }
```

### 403 — Endpoint requires Core/Pro/Enterprise

```json theme={null}
{ "error": "This endpoint requires a Core, Pro, or Enterprise role. Contact an administrator to request access." }
```

### 403 — `unverified=true` requires Pro/Enterprise

```json theme={null}
{
  "error": "The 'unverified' parameter requires a Pro or Enterprise role.",
  "upgrade_url": "https://opensourcemalware.com/pro-features"
}
```

### 400 — Invalid `hours`

```json theme={null}
{ "error": "hours parameter must be an integer between 1 and 24" }
```

### 400 — Missing `ecosystem`

```json theme={null}
{ "error": "ecosystem parameter is required" }
```

### 500 — Query failed

```json theme={null}
{ "error": "Failed to query threats" }
```

***

## threat-data

### 401 — Missing API token

```json theme={null}
{ "error": "API token required. Provide token in Authorization header or apikey query parameter." }
```

### 401 — Invalid or inactive token

```json theme={null}
{ "error": "Invalid or inactive API token" }
```

### 403 — Requires Pro/Editor/Admin

```json theme={null}
{ "error": "Access denied. This endpoint requires Pro, Editor, or Admin access." }
```

### 400 — Missing `threat_id`

```json theme={null}
{ "error": "Missing required parameter: threat_id" }
```

### 400 — Invalid UUID

```json theme={null}
{ "error": "Invalid threat_id format. Must be a valid UUID." }
```

### 404 — Not found or not verified/modified

```json theme={null}
{ "error": "Threat not found or not in verified/modified status." }
```

***

## query-by-username

### 401 — Missing API token

```json theme={null}
{ "error": "Missing API token. Provide via Authorization header or apikey query parameter." }
```

### 401 — Invalid token

```json theme={null}
{ "error": "Invalid API token" }
```

### 401 — Inactive token

```json theme={null}
{ "error": "API token is inactive" }
```

### 403 — Requires Pro/Enterprise

```json theme={null}
{ "error": "Pro or Enterprise account required for this endpoint. Please contact an administrator at info@sourcecodered.com to request access." }
```

### 400 — Missing params

```json theme={null}
{
  "error": "Missing required parameters. Both ecosystem and username are required.",
  "example": "/query-by-username?ecosystem=npm&username=malicious-publisher"
}
```

### 500 — Failed to verify permissions

```json theme={null}
{ "error": "Failed to verify permissions" }
```

### 500 — Database query failed

```json theme={null}
{ "error": "Database query failed" }
```

***

## Write endpoints

`submit-threat-report` and `modify-threat-report` rate limits are per-hour (submission/modification counts) rather than per-minute.

## submit-threat-report

### 401 — No Authorization header

```json theme={null}
{ "error": "Authorization required" }
```

### 401 — Invalid API token (`osm_...`)

```json theme={null}
{ "error": "Invalid API token" }
```

### 429 — IP rate limit

```json theme={null}
{ "error": "Rate limit exceeded for your IP address. Please try again later." }
```

### 429 — Submission rate limit (per hour)

```json theme={null}
{ "error": "Rate limit exceeded. Maximum 10 submissions per hour." }
```

<Note>
  10/hour for Free users. Limit may be increased by an admin.
</Note>

### 403 — New-user unverified cap

```json theme={null}
{
  "error": "New users are limited to 3 unverified reports. You currently have 3 unverified reports. Once 3 of your reports are verified, this limit will be removed.",
  "verified_reports": 0,
  "unverified_reports": 3
}
```

### 405 — Method not allowed

```json theme={null}
{ "error": "Method not allowed" }
```

### 400 — Missing required fields

```json theme={null}
{ "error": "Missing required fields: report_type, resource_identifier, and threat_description are required" }
```

### 409 — Duplicate package in registry

```json theme={null}
{
  "error": "A threat report for this package in this registry already exists. Please use the \"Update Report\" functionality to modify the existing report.",
  "existingThreatId": "<uuid>",
  "packageName": "<package-name>",
  "registry": "npm",
  "status": "verified"
}
```

### 500 — Existing-package lookup failed

```json theme={null}
{
  "error": "Failed to check for existing package",
  "details": "<postgres error message>"
}
```

### 500 — Threat insert failed

```json theme={null}
{
  "error": "Failed to create threat report",
  "details": "<postgres error message>"
}
```

### 500 — Threat details insert failed (threat was rolled back)

```json theme={null}
{
  "error": "Failed to create threat details",
  "details": "<postgres error message>"
}
```

### 500 — Catch-all

```json theme={null}
{
  "error": "Internal server error",
  "details": "<exception message>"
}
```

***

## modify-threat-report

### 401 — No Authorization header

```json theme={null}
{ "error": "Authorization required" }
```

### 401 — Invalid API token

```json theme={null}
{ "error": "Invalid API token" }
```

### 429 — IP rate limit (whitelisted IPs bypass)

```json theme={null}
{ "error": "Rate limit exceeded for your IP address. Please try again later." }
```

### 429 — Modification rate limit (per hour)

```json theme={null}
{ "error": "Rate limit exceeded. Maximum 30 modifications per hour." }
```

<Note>
  30/hour for standard users. This limit may be increased by an admin.
</Note>

### 405 — Method not allowed

```json theme={null}
{ "error": "Method not allowed" }
```

### 400 — No target identifier supplied

```json theme={null}
{ "error": "Missing required field: either threat_id, package_name, or resource_identifier is required" }
```

### 404 — Lookup by `package_name` returned nothing

```json theme={null}
{ "error": "No threat report found for this package name" }
```

### 404 — Lookup by `resource_identifier` returned nothing

```json theme={null}
{ "error": "No threat report found for this resource_identifier" }
```

### 404 — `threat_id` not found

```json theme={null}
{ "error": "Threat report not found" }
```

### 500 — Lookup by package\_name failed

```json theme={null}
{
  "error": "Failed to lookup threat by package name",
  "details": "<postgres error message>"
}
```

### 500 — Lookup by resource\_identifier failed

```json theme={null}
{
  "error": "Failed to lookup threat by resource_identifier",
  "details": "<postgres error message>"
}
```

### 500 — Fetch existing threat failed

```json theme={null}
{
  "error": "Failed to fetch threat report",
  "details": "<postgres error message>"
}
```

### 500 — Version-creation prefetch failed (pro-user edit path)

```json theme={null}
{ "error": "Failed to fetch threat for version creation" }
```

### 500 — Save proposed changes failed (pro-user edit path)

```json theme={null}
{
  "error": "Failed to save proposed changes",
  "details": "<postgres error message>"
}
```

### 500 — Admin/editor threat update failed

```json theme={null}
{
  "error": "Failed to update threat report",
  "details": "<postgres error message>"
}
```

### 500 — Admin/editor threat details update failed

```json theme={null}
{
  "error": "Failed to update threat details",
  "details": "<postgres error message>"
}
```

### 500 — Catch-all

```json theme={null}
{
  "error": "Internal server error",
  "details": "<exception message>"
}
```
