{"record":{"id":"3c64dc036abacb2d","repo":"koala73/worldmonitor","slug":"expected-a-six-character-hexadecimal-icao-address","errorCode":null,"errorMessage":"Expected a six-character hexadecimal ICAO address","messagePattern":"Expected a six-character hexadecimal ICAO address","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"warning","filePath":"server/worldmonitor/aviation/v1/track-aircraft.ts","lineNumber":122,"sourceCode":"    if (req.icao24) return `aviation:track:icao:${req.icao24}:v2`;\n    if (req.callsign) return `aviation:track:callsign:${req.callsign.toUpperCase()}:v2`;\n    return 'aviation:track:all:v2';\n}\n\n// Response-level source values (TrackAircraftResponse.source):\n//   'opensky'           — data from OpenSky via relay\n//   'wingbits'          — data from Wingbits via relay\n//   'none'              — all real sources returned empty or failed; positions = []\nexport async function trackAircraft(\n    ctx: ServerContext,\n    req: TrackAircraftRequest,\n): Promise<TrackAircraftResponse> {\n    const rawIcao24 = req.icao24 ?? '';\n    const rawCallsign = req.callsign ?? '';\n    if (rawIcao24.length > 16 || rawCallsign.length > 16) throw new ApiError(400, 'Aircraft identifier is too long', '');\n    const icao24 = rawIcao24.trim().toLowerCase();\n    const callsign = rawCallsign.trim().toUpperCase();\n    if (rawIcao24 && !/^[0-9a-f]{6}$/.test(icao24)) throw new ApiError(400, 'Expected a six-character hexadecimal ICAO address', '');\n    if (rawCallsign && !/^[A-Z0-9]{1,8}$/.test(callsign)) throw new ApiError(400, 'Expected an alphanumeric callsign of at most eight characters', '');\n    if (![req.swLat, req.swLon, req.neLat, req.neLon].every(Number.isFinite)) throw new ApiError(400, 'Expected finite viewport coordinates', '');\n    const lat1 = Math.max(-90, Math.min(90, req.swLat));\n    const lat2 = Math.max(-90, Math.min(90, req.neLat));\n    const lon1 = Math.max(-180, Math.min(180, req.swLon));\n    const lon2 = Math.max(-180, Math.min(180, req.neLon));\n    req = { ...req, icao24, callsign, swLat: Math.min(lat1, lat2), neLat: Math.max(lat1, lat2), swLon: Math.min(lon1, lon2), neLon: Math.max(lon1, lon2) };\n    if (icao24 || callsign) await admitIdentifierLookup(ctx.request);\n\n    const redistributableOnly = requiresRedistributableProviders(ctx.request);\n    const cacheKey = `${await buildCacheKey(req)}${redistributableOnly ? ':redistributable' : ''}`;\n\n    let result: { positions: PositionSample[]; source: string } | null = null;\n    try {\n        const positiveTtl = req.callsign ? CALLSIGN_CACHE_TTL : CACHE_TTL;\n        const negativeTtl = req.callsign ? CALLSIGN_NEGATIVE_TTL : CACHE_TTL;\n        result = await cachedFetchJson<{ positions: PositionSample[]; source: string }>(\n            cacheKey, positiveTtl, async () => {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/server/worldmonitor/aviation/v1/track-aircraft.ts#L104-L140","documentation":"trackAircraft requires that a provided icao24, once trimmed and lowercased, matches /^[0-9a-f]{6}$/ — exactly six hexadecimal characters. Empty is allowed (then callsign must be supplied); any other shape throws ApiError(400, 'Expected a six-character hexadecimal ICAO address').","triggerScenarios":"Calling track-aircraft with icao24 like 'ABC123' (uppercase is fine only because it is lowercased first, but 'G' letters outside a-f are not), 5- or 7-character hex, or identifiers containing separators ('40-6B-7F').","commonSituations":"Passing registration numbers ('D-ABCD') or flight numbers as icao24; copying ICAO24 with spaces/dashes from ADS-B sites; truncating a longer hex string by hand.","solutions":["Send exactly six hex characters, e.g. '4ca2b6'","Strip separators and validate with /^[0-9a-fA-F]{6}$/ before calling","If you only have a callsign, omit icao24 entirely and pass callsign"],"exampleFix":"// before\nawait trackAircraft(ctx, { icao24: '4C-A2-B6' });\n// after\nconst icao24 = raw.replace(/[^0-9a-fA-F]/g, '').toLowerCase();\nawait trackAircraft(ctx, { icao24 });","handlingStrategy":"validation","validationCode":"if (icao24 && !/^[0-9a-fA-F]{6}$/.test(icao24.trim())) throw new Error('icao24 must be 6 hex characters');","typeGuard":"const isIcao24 = (v: unknown): v is string => typeof v === 'string' && /^[0-9a-fA-F]{6}$/.test(v.trim());","tryCatchPattern":"try {\n  return await trackAircraft(ctx, { icao24 });\n} catch (e) {\n  if (e instanceof ApiError && e.status === 400) {\n    return { error: e.message, hint: 'expected six hex chars, e.g. 4ca2b6' };\n  }\n  throw e;\n}","preventionTips":["Strip dashes/spaces from copied ICAO24 values","Lowercase before sending to match server normalization","Fall back to callsign-only lookup when you lack a valid ICAO24"],"tags":["validation","format","aviation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-22T01:50:49.965Z","contentChangedAt":"2026-09-22T01:50:49.965Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}