{"record":{"id":"c4ab05f289dfd220","repo":"mastra-ai/mastra","slug":"platform-integration-missing-required-config-fiel","errorCode":null,"errorMessage":"Platform integration: missing required config field(s): ${missing.join(', ')}.","messagePattern":"Platform integration: missing required config field\\(s\\): (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/platform/api-client.ts","lineNumber":46,"sourceCode":"  readonly retryAfterSeconds: number | null;\n\n  constructor(message: string, status: number, retryAfterSeconds: number | null = null) {\n    super(message);\n    this.name = 'PlatformApiError';\n    this.status = status;\n    this.retryAfterSeconds = retryAfterSeconds;\n  }\n}\n\nexport class PlatformApiClient {\n  readonly #baseUrl: string;\n  readonly #accessToken: string;\n  readonly #fetch: typeof fetch;\n\n  constructor(config: PlatformApiClientConfig) {\n    const missing = ['baseUrl', 'accessToken'].filter(field => !config[field as keyof PlatformApiClientConfig]);\n    if (missing.length > 0) {\n      throw new Error(`Platform integration: missing required config field(s): ${missing.join(', ')}.`);\n    }\n    this.#baseUrl = config.baseUrl.replace(/\\/+$/, '');\n    this.#accessToken = config.accessToken;\n    this.#fetch = config.fetchImpl ?? globalThis.fetch;\n  }\n\n  async request<T>(\n    method: string,\n    path: string,\n    body?: unknown,\n    options?: { signal?: AbortSignal; actingUserId?: string },\n  ): Promise<T> {\n    const response = await this.#send(method, path, body, options);\n    if (!response.ok) {\n      const message = redact(await extractError(response), this.#accessToken);\n      const retryAfterSeconds = parseRetryAfter(response.headers.get('retry-after'));\n      logPlatformError('Platform API request failed', {\n        method,","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/platform/api-client.ts#L28-L64","documentation":"The `PlatformApiClient` constructor validates its config and throws when any of the required fields `baseUrl` or `accessToken` is missing/empty, listing the offending field names in the message. This catches programmatically-constructed (not env-derived) configurations before any network call is made.","triggerScenarios":"Constructing `new PlatformApiClient(config)` where `config.baseUrl` or `config.accessToken` is `undefined`, `null`, or an empty string — e.g. building the config object by hand, spreading a partial options object, or a custom config loader that returned incomplete values instead of using `platformApiClientConfigFromEnv`.","commonSituations":"Hardcoding a client in tests/scripts and forgetting `accessToken`; a factory that conditionally sets fields and skips empty ones; reading config from a parsed JSON/YAML file where a key is absent; renaming a field in the config type without updating all construction sites.","solutions":["Populate both `baseUrl` and `accessToken` in the `PlatformApiClientConfig` object before construction.","Prefer `platformApiClientConfigFromEnv()` to build the config so missing values fail with the clearer env-var error instead.","Add a pre-construction check/logging of the config keys to spot which field is absent.","If fields come from a config file, validate the parsed object's shape before passing it to the constructor."],"exampleFix":"// before\nconst client = new PlatformApiClient({ baseUrl: 'https://api.example.com' });\n// after\nconst client = new PlatformApiClient({\n  baseUrl: 'https://api.example.com',\n  accessToken: process.env.MASTRA_PLATFORM_ACCESS_TOKEN!,\n});","handlingStrategy":"validation","validationCode":"function assertPlatformConfig(config: Partial<PlatformApiClientConfig>): asserts config is PlatformApiClientConfig {\n  const missing = (['baseUrl', 'accessToken'] as const).filter(k => !config[k]);\n  if (missing.length) throw new Error(`PlatformApiClient config missing: ${missing.join(', ')}`);\n}","typeGuard":"function isCompletePlatformConfig(c: Partial<PlatformApiClientConfig>): c is PlatformApiClientConfig {\n  return typeof c.baseUrl === 'string' && c.baseUrl.length > 0 && typeof c.accessToken === 'string' && c.accessToken.length > 0;\n}","tryCatchPattern":"try {\n  const client = new PlatformApiClient(config);\n} catch (e) {\n  if (e.message.startsWith('Platform integration: missing required config field')) {\n    console.error('Invalid PlatformApiClient config:', e.message);\n    config = platformApiClientConfigFromEnv(); // fall back to env-derived config\n    return new PlatformApiClient(config);\n  }\n  throw e;\n}","preventionTips":["Build config via platformApiClientConfigFromEnv() instead of hand-assembling objects.","Type the config as full PlatformApiClientConfig (not Partial) so TypeScript catches missing fields at compile time.","Validate parsed config-file objects before constructing the client.","After renaming config fields, grep all construction sites.","In tests, use a shared fixture factory that always sets baseUrl and accessToken."],"tags":["configuration","validation","constructor","platform"],"backgroundTag":"missing-config-field","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}