{"record":{"id":"ba13fdbd29373f51","repo":"Wei-Shaw/sub2api","slug":"api-error","errorCode":"api_error","errorMessage":"DeviceCheck is not supported on this Mac","messagePattern":"DeviceCheck is not supported on this Mac","errorType":"http","errorClass":"LiveAttestationUnavailableError","httpStatus":503,"severity":"error","filePath":"backend/internal/platform/liveattestation/attestation_darwin.go","lineNumber":270,"sourceCode":"function float(value) {\n  if (Number.isSafeInteger(value) && value >= 0) return uint(value);\n  const out = Buffer.allocUnsafe(9);\n  out[0] = 251;\n  out.writeDoubleBE(value, 1);\n  return out;\n}\nfunction array(values) { return Buffer.concat([head(128, values.length), ...values]); }\nfunction map(entries) {\n  return Buffer.concat([head(160, entries.length), ...entries.flatMap(([key, value]) => [uint(key), value])]);\n}\nfunction field(key, value) { return Buffer.concat([text(key), text(value)]); }\nfunction base64url(value) {\n  return value.toString(\"base64\").replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/u, \"\");\n}\n\n(async () => {\n  const result = await addon.generateToken();\n  if (!result || !result.supported) throw new Error(\"DeviceCheck is not supported on this Mac\");\n  if (!result.tokenBase64) throw new Error(\"DeviceCheck returned no token\");\n  const fingerprint = map([\n    [0, uint(signals.schemaVersion)],\n    [1, array(signals.preferredLanguages.map(text))],\n    [2, text(signals.locale)],\n    [3, text(signals.timezone)],\n    [4, uint(signals.screenSizeSum)],\n    [5, float(signals.screenScale)],\n    [6, text(signals.appSessionId)]\n  ]);\n  const fields = [\n    field(\"token\", result.tokenBase64),\n    field(\"bundle_id\", bundleID),\n    Buffer.concat([text(\"f\"), head(64, fingerprint.length), fingerprint])\n  ];\n  if (result.latencyMs != null) {\n    fields.push(Buffer.concat([text(\"t\"), float(result.latencyMs)]));\n  }","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/platform/liveattestation/attestation_darwin.go#L252-L288","documentation":"Thrown by a JavaScript snippet embedded in backend/internal/platform/liveattestation/attestation_darwin.go. It calls a native addon's generateToken() (wrapping Apple DeviceCheck / DCDevice.generateToken) and throws when the result is falsy or result.supported is false, meaning the host Mac cannot produce a DeviceCheck token. DeviceCheck only works on real Mac hardware with macOS 10.15+, a signed app/binary with the proper Apple team, and working network access to Apple. In a VM, Hackintosh, CI runner, or unsigned dev build the addon commonly reports supported:false.","triggerScenarios":"Calling the attestation flow on macOS where addon.generateToken() resolves with {supported:false} or an empty object. Specific causes: running on macOS < 10.15, inside a VM (DeviceCheck unsupported), missing/incorrect code-signing identity or entitlements for the native addon, no network path to Apple's DeviceCheck servers, or a Hackintosh without valid Secure Enclave/IMEI-era hardware support.","commonSituations":"Developers running the Go backend locally on an unsigned debug build; CI macOS runners (DeviceCheck frequently fails there); M-series Macs inside virtualization (UTM/Parallels); deployment where the binary is re-signed/ad-hoc signed and loses the original signing team.","solutions":["Run the backend on a real, signed macOS host with macOS 10.15+ and verify addon.generateToken() returns supported:true in isolation.","Check that the native addon binary and the host process are code-signed by the same team that configured the DeviceCheck capability in the Apple developer account.","Add a preflight capability probe (call generateToken once at startup) and fall back to a non-attestation code path when supported is false instead of throwing mid-request.","If running in CI or a VM, gate the attestation feature behind a config flag so those environments skip DeviceCheck."],"exampleFix":"// before\nconst result = await addon.generateToken();\nif (!result || !result.supported) throw new Error(\"DeviceCheck is not supported on this Mac\");\n\n// after\nconst result = await addon.generateToken();\nif (!result || !result.supported) {\n  const err = new Error(\"DeviceCheck is not supported on this Mac\");\n  err.code = 'DEVICECHECK_UNSUPPORTED';\n  throw err;\n}\n// caller:\ntry { token = await getAttestationToken(); }\ncatch (e) { if (e.code === 'DEVICECHECK_UNSUPPORTED') return skipAttestation(); throw e; }","handlingStrategy":"fallback","validationCode":"// Before starting attestation, probe once:\nconst probe = await addon.generateToken();\nexport const deviceCheckAvailable = !!(probe && probe.supported);","typeGuard":null,"tryCatchPattern":"try {\n  token = await getAttestationToken();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('DeviceCheck is not supported')) {\n    return skipAttestationGracefully(); // known-environment degradation\n  }\n  throw e;\n}","preventionTips":["Gate DeviceCheck attestation behind a config flag so CI/VM environments skip it","Code-sign the binary and addon with the team that owns the DeviceCheck capability","Probe generateToken() at startup and cache the supported flag instead of failing per request"],"tags":["macos","devicecheck","attestation","native-addon","hardware"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}