mastra-ai/mastra · error · MastraError

EXPERIMENT_HAS_TARGET

EXPERIMENT_HAS_TARGET

Error message

Experiment ${args.experimentId} has a target (${experiment.targetType} "${experiment.targetId}"); results are produced by Mastra, not ingested. Use runExperimentItem instead.

What it means

submitExperimentResult ingests externally produced results and is only valid for targetless experiments (targetType null). If the experiment has a bound target, Mastra itself produces results via runExperimentItem, so external ingestion is rejected to prevent double/conflicting results.

Source

Thrown at packages/core/src/datasets/dataset.ts:919

    attempt?: number;
    input?: unknown;
    output?: unknown;
    groundTruth?: unknown;
    error?: { message: string; stack?: string; code?: string } | null;
    startedAt?: Date;
    completedAt?: Date;
    traceId?: string;
    scores?: {
      scorerId: string;
      scorerName?: string;
      score: number;
      reason?: string;
      metadata?: Record<string, unknown>;
    }[];
  }): Promise<ExperimentResult> {
    const experiment = await this.#getOwnedExperiment(args.experimentId);
    if (experiment.targetType !== null) {
      throw new MastraError({
        id: 'EXPERIMENT_HAS_TARGET',
        text: `Experiment ${args.experimentId} has a target (${experiment.targetType} "${experiment.targetId}"); results are produced by Mastra, not ingested. Use runExperimentItem instead.`,
        domain: 'STORAGE',
        category: 'USER',
      });
    }
    if (experiment.status === 'completed' || experiment.status === 'failed') {
      throw new MastraError({
        id: 'EXPERIMENT_ALREADY_FINALIZED',
        text: `Experiment ${args.experimentId} is already ${experiment.status}; no further results can be submitted`,
        domain: 'STORAGE',
        category: 'USER',
      });
    }

    const datasetsStore = await this.#getDatasetsStore();
    const item = await datasetsStore.getItemById({
      id: args.itemId,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check experiment.targetType; only call submitExperimentResult when it is null
  2. Use runExperimentItem for experiments with targets and let Mastra produce the results
  3. Create a separate targetless experiment if results genuinely come from outside Mastra

Example fix

// before
await dataset.submitExperimentResult({ experimentId: 'exp-1', itemId: 'item-1', ... }); // exp-1 targets agent
// after
if (exp.targetType === null) {
  await dataset.submitExperimentResult({ ... });
} else {
  await dataset.runExperimentItem({ experimentId: 'exp-1', itemId: 'item-1' });
}
Defensive patterns

Strategy: validation

Validate before calling

const exp = await getExperimentById(experimentId);
if (exp && exp.targetType !== null) throw new Error('Experiment has a target; use runExperimentItem');

Type guard

function isTargetless(exp) { return exp !== null && exp.targetType === null; }

Try / catch

try {
  await dataset.submitExperimentResult(args);
} catch (e) {
  if (isMastraError(e) && e.id === 'EXPERIMENT_HAS_TARGET') {
    await dataset.runExperimentItem({ experimentId: args.experimentId, itemId: args.itemId });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling dataset.submitExperimentResult({ experimentId, ... }) on an experiment created with targetType/targetId set (e.g. bound to an agent or tool).

Common situations: Pipelines that submit results for all experiments indiscriminately; a target was added to an experiment that previously accepted external results; copying ingestion code between targetless and targeted experiment flows.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/9a0dbea309bafc99. Report an issue: GitHub.