hcengineering/platform · error · ApiError
ApiError
Error message
ApiError
What it means
The analytics-collector's wrapRequest wrapper extracts a bearer token from request headers; if extractToken returns undefined, it throws ApiError(401), rejecting unauthenticated requests before the handler runs. This is the service's authentication gate for all wrapped routes.
Source
Thrown at services/analytics-collector/pod-analytics-collector/src/server.ts:38
import { Token } from '@hcengineering/server-token'
import cors from 'cors'
import express, { type Express, type NextFunction, type Request, type Response } from 'express'
import { type Server } from 'http'
import config from './config'
import { ApiError } from './error'
import { geoFieldMapping, getAllPossibleIps, getClientIp, getGeoLocationFromIp } from './geoip'
type AsyncRequestHandler = (req: Request, res: Response, token: Token, next: NextFunction) => Promise<void>
const handleRequest = async (
fn: AsyncRequestHandler,
req: Request,
res: Response,
next: NextFunction
): Promise<void> => {
const token = extractToken(req.headers)
if (token === undefined) {
throw new ApiError(401)
}
try {
await fn(req, res, token, next)
} catch (err: unknown) {
next(err)
}
}
const wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, next: NextFunction) => {
void handleRequest(fn, req, res, next)
}
function isContentValid (body: any[]): boolean {
return !body.some((it) => {
if (it == null) return true
if (!('event' in it)) return true
if (!('properties' in it)) return true
if (!('timestamp' in it)) return trueView on GitHub (pinned to 63e28dc964)
Solutions
- Send a valid Authorization header (e.g. 'Bearer <token>') on every request to wrapped routes
- Inspect the raw request headers (curl -v / gateway logs) to confirm the header survives proxies
- Match the header format expected by extractToken in services/analytics-collector/pod-analytics-collector/src/server.ts
- Verify API client/SDK configuration includes the auth token for the correct environment
Example fix
// before curl -X POST https://collector/collect -d '[...]' // after curl -X POST https://collector/collect -H 'Authorization: Bearer <token>' -d '[...]'
Defensive patterns
Strategy: validation
Validate before calling
// check the token exists before sending
if (!authToken) throw new Error('Analytics collector auth token is not configured')
const headers = { Authorization: `Bearer ${authToken}`, 'Content-Type': 'application/json' } Try / catch
try {
await collector.post('/collect', body, { headers })
} catch (err) {
if (err.response?.status === 401) {
// refresh token / fail fast with a clear config error
} else throw err
} Prevention
- Centralize auth-header injection in one HTTP client
- Assert token presence at startup, not per request
- Verify proxies do not strip the Authorization header
When it happens
Trigger: POST /collect (or any wrapped route) called without an Authorization header, with a malformed header that extractToken cannot parse, or with an empty token.
Common situations: Client forgot to set the Authorization header; a proxy/gateway stripped the header; SDK or curl command omits the token; header prefix (e.g. 'Bearer ') mismatched with what extractToken expects.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/ffd45b1784b2f6bd.
Report an issue: GitHub.