JuliusBrussee/caveman · critical · Error

cave_harness_incomplete_evidence

cave_harness_incomplete_evidence

Error message

cave_harness_incomplete_evidence

What it means

Returned by validateRuntimeIdentity when the connected identity's current_user differs from session_user. The package requires the authenticated login identity and the effective identity to be identical, because Postgres allows session_user to run SET ROLE NONE and reclaim its original (possibly privileged) identity, which would silently escape the tenant-isolation role. Any connection that logged in as one role and SET ROLE'd into another is rejected.

Source

Thrown at packages/agent/src/adapters.ts:354

  inputTokens: number;
  outputTokens: number;
  cacheReadTokens: number;
  cacheWriteTokens: number;
  reasoningTokens: number;
  totalTokens: number;
}

function harnessExecution(input: {
  request: Readonly<HarnessRequest>;
  text: string;
  provider: string;
  model: string;
  usage: NormalizedUsage;
  latencyMs: number;
}): HarnessExecution {
  const expected = expectedProviderModel(input.request.plan);
  if (input.provider !== expected.provider || input.model !== expected.model) {
    throw new Error("cave_harness_incomplete_evidence");
  }
  const priced = validateProviderUsage({
    provider: input.provider,
    model: input.model,
    ...input.usage,
  }, { requirePriced: true });
  return {
    terminal: true,
    text: input.text,
    provider: input.provider,
    model: input.model,
    ...input.usage,
    costUsd: priced.catalogCostUsd,
    usageBasis: "provider_reported",
    priceBasis: "public_catalog",
    evaluatedTransformIDs: [...input.request.evaluatedTransformIDs],
    appliedTransformIDs: [...input.request.appliedTransformIDs],
    recoveryResolved: input.request.recoveryResolved,

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Create a dedicated LOGIN role for the runtime pool (e.g. app_runtime) and put its credentials in DATABASE_URL so session_user == current_user from the start
  2. Remove any SET ROLE from connection startup SQL, pool 'after_connect' hooks, or PgBouncer startup parameters
  3. If PgBouncer is in front, use transaction pooling with clean state or bypass it for the runtime pool connections
  4. Re-run the identity query (SELECT current_user, session_user) with the same URL via psql to confirm both match

Example fix

# before
DATABASE_URL=postgres://app_owner:...@db:5432/app?sslmode=verify-full
# app_owner does: SET ROLE app_runtime;  -> current_user != session_user -> rejected

# after
CREATE ROLE app_runtime LOGIN PASSWORD '...' NOLOGIN FALSE;
GRANT app_runtime TO app_owner; -- if needed for grants
DATABASE_URL=postgres://app_runtime:...@db:5432/app?sslmode=verify-full
Defensive patterns

Strategy: validation

Validate before calling

// Assert identity alignment before constructing the runtime pool:
func preflightIdentity(ctx context.Context, dbURL string) error {
    conn, err := pgx.Connect(ctx, dbURL)
    if err != nil { return err }
    defer conn.Close(ctx)
    var cur, sess string
    if err := conn.QueryRow(ctx, "SELECT current_user, session_user").Scan(&cur, &sess); err != nil {
        return err
    }
    if cur != sess {
        return fmt.Errorf("login as the runtime role directly; %q logged in but effective role is %q (SET ROLE is not permitted)", sess, cur)
    }
    return nil
}

Type guard

func isIdentityMismatchErr(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "postgres: runtime current_user")
}

Try / catch

if err := preflightIdentity(ctx, dbURL); err != nil {
    return err // fail with an operator-actionable message before pool construction
}
pool, err := postgresconfig.NewPool(ctx, dbURL)

Prevention

When it happens

Trigger: Connecting with a superuser/owner login and issuing SET ROLE app_runtime before handing the connection to the pool constructor; a proxy or pooler (PgBouncer) that reuses sessions with an active SET ROLE; DATABASE_URL credentials of an admin user with a startup parameter that changes the role.

Common situations: Dev setups where the operator connects as postgres and 'drops down' to the runtime role instead of creating a dedicated login; connection strings with options='-c role=app_runtime'; PgBouncer session pooling leaking role state between tenants; migration tools that connect as owner and then run the app in the same process.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/3b2a617ba4f0ec7d. Report an issue: GitHub.