{"record":{"id":"4359d6b23c566c1c","repo":"JuliusBrussee/caveman","slug":"cave-mastra-terminal-failure","errorCode":"cave_mastra_terminal_failure","errorMessage":"cave_mastra_terminal_failure","messagePattern":"cave_mastra_terminal_failure","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/agent/src/adapters.ts","lineNumber":320,"sourceCode":"    throw new Error(\"cave_mastra_max_steps_invalid\");\n  }\n  assertSupportedUpstream(identity, MASTRA_VERSION, \"mastra\", \"@mastra/core\");\n  return createHarnessAdapter(\"mastra\", identity, {\n    package: \"@mastra/core/agent\",\n    class: \"Agent\",\n    method: \"generate\",\n    usage: \"FullOutput.totalUsage\",\n    ...(maxSteps === undefined ? {} : { preExecutionControls: { maxSteps } }),\n  }, async (request) => {\n    const startedAt = performance.now();\n    const response = await agent.generate(request.prompt, {\n      maxProcessorRetries: 0,\n      runId: request.runID,\n      ...(maxSteps === undefined ? {} : { maxSteps }),\n      ...(request.signal === undefined ? {} : { abortSignal: request.signal }),\n    });\n    if (response.error !== undefined || terminalFinishReason(response.finishReason) === false) {\n      throw new Error(\"cave_mastra_terminal_failure\");\n    }\n    const expected = expectedProviderModel(request.plan);\n    const actualModel = normalizedResponseModel(response.response?.modelId, expected.provider);\n    return harnessExecution({\n      request,\n      text: response.text,\n      provider: expected.provider,\n      model: actualModel,\n      usage: usageFromMastra(response.totalUsage ?? response.usage, request.plan.reasoning !== \"none\"),\n      latencyMs: Math.round(performance.now() - startedAt),\n    });\n  });\n}\n\ninterface NormalizedUsage {\n  inputTokens: number;\n  outputTokens: number;\n  cacheReadTokens: number;","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L302-L338","documentation":"Returned by the runtime-identity probe when the catalog query that reads current_user, session_user, superuser/bypassrls flags, role membership, and tenant-table ownership fails to execute or scan. This query runs on every runtime pool as a defense-in-depth check; this particular error means the introspection itself broke (query error, connection problem, scan/type mismatch), not that the identity is wrong.","triggerScenarios":"Calling the runtime-pool constructor with a connection that drops mid-query, a database user that lacks read access to pg_roles/pg_class/information_schema, an expectedRole containing characters that break the embedded query, or a server version whose catalog columns differ from what the query selects.","commonSituations":"The database user was granted only DML and cannot read pg_catalog views; network interruption between dial and the identity probe; migrating to a managed Postgres (RDS/Cloud SQL) that restricts some catalog visibility; role names with quotes or unusual characters injected from config.","solutions":["Read the wrapped error first: if it is a network/canceled error, fix connectivity or the pool's connect timeout; the probe is retried on the next pool creation","Grant the runtime role SELECT on the catalog views used (pg_roles, pg_catalog.pg_class, information_schema.columns) or membership in a role that can read them","Sanitize expectedRole: validate it matches ^[A-Za-z_][A-Za-z0-9_]*$ before it reaches the query","Run the query manually as the same database user (psql) to see which catalog access fails"],"exampleFix":"-- before: runtime role cannot read catalogs\nCREATE ROLE app_runtime LOGIN PASSWORD '...';\nGRANT SELECT ON ALL TABLES IN SCHEMA public TO app_runtime;\n-- identity probe fails: permission denied for table pg_roles\n\n-- after\nGRANT pg_read_all_data TO app_runtime;  -- or targeted catalog grants\n","handlingStrategy":"try-catch","validationCode":"// Verify the probe can run as the configured role before app start:\nfunc canInspectIdentity(ctx context.Context, conn *pgx.Conn, expectedRole string) error {\n    var ok bool\n    err := conn.QueryRow(ctx, `SELECT pg_has_role(current_user, $1, 'member')`, expectedRole).Scan(&ok)\n    if err != nil {\n        return fmt.Errorf(\"catalog read failed for identity probe; grant pg_catalog read access: %w\", err)\n    }\n    return nil\n}","typeGuard":"func isIdentityProbeErr(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"postgres: inspect runtime identity:\")\n}\n\nfunc isTransientDBErr(err error) bool {\n    var netErr net.Error\n    return errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"pool, err := newRuntimePool(ctx, dbURL, expectedRole)\nif err != nil {\n    if isIdentityProbeErr(err) && isTransientDBErr(errors.Unwrap(err)) {\n        // transient: retry pool construction with backoff\n        pool, err = retryNewRuntimePool(ctx, dbURL, expectedRole, 3)\n    }\n    if err != nil { return err }\n}","preventionTips":["Grant the runtime role read access to pg_catalog views used by the probe (or pg_read_all_data)","Validate expectedRole format (^[A-Za-z_][A-Za-z0-9_]*$) at config load","Retry pool construction once on transient network errors at startup","Run the identity SQL manually with psql as the same role when triaging"],"tags":["postgres","security","rls","catalog","startup"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}