thedotmack/claude-mem · error

storeObservation requires a non-empty title

Error message

storeObservation requires a non-empty title

What it means

storeObservation is a single-row wrapper around storeObservations. storeObservations silently skips rows with empty titles, which would leave the wrapper with no inserted id to return; to keep its non-nullable {id, createdAtEpoch} contract, it validates the title up front and throws instead.

Solutions

  1. Set a non-empty observation.title before calling storeObservation (e.g. derive from content or use a placeholder).
  2. If the title is genuinely optional, call storeObservations with a one-element array instead and check whether an id was returned.
  3. Add a caller-side guard that falls back to a default title when the source text is empty.

Example fix

// before
await store.storeObservation(sessionId, project, { title, content });
// after
await store.storeObservation(sessionId, project, {
  title: title && title.trim() ? title : content.slice(0, 80) || 'untitled observation',
  content
});
Defensive patterns

Strategy: validation

Validate before calling

if (!observation.title || observation.title.trim() === '') {
  throw new Error('Cannot store observation without a title');
}
await store.storeObservation(sessionId, project, observation);

Type guard

function hasTitle(o: { title?: string }): o is { title: string } {
  return typeof o.title === 'string' && o.title.trim() !== '';
}

Prevention

When it happens

Trigger: Calling SessionStore.storeObservation(memorySessionId, project, observation) where observation.title is undefined, null, an empty string, or a whitespace-only string (e.g. title.trim() === '').

Common situations: Building an observation object programmatically where the title extraction failed (e.g. summarizer returned nothing, a hook passed a prompt with no content), or deserializing records from an older DB/export where the title field was optional.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/a7e434e20ae03580. Report an issue: GitHub.

Appendix: source

Thrown at src/services/sqlite/SessionStore.ts:3039

      facts: string[];
      narrative: string | null;
      concepts: string[];
      files_read: string[];
      files_modified: string[];
      agent_type?: string | null;
      agent_id?: string | null;
      metadata?: string | null;
    },
    promptNumber?: number,
    discoveryTokens: number = 0,
    overrideTimestampEpoch?: number,
    generatedByModel?: string
  ): { id: number; createdAtEpoch: number } {
    // storeObservations skips empty-title rows, which would leave no id to return here.
    // This wrapper stores exactly one observation, so require a title up front rather than
    // returning an undefined id.
    if (!observation.title || observation.title.trim() === '') {
      throw new Error('storeObservation requires a non-empty title');
    }

    const result = this.storeObservations(
      memorySessionId,
      project,
      [observation],
      null,
      promptNumber,
      discoveryTokens,
      overrideTimestampEpoch,
      generatedByModel
    );

    return { id: result.observationIds[0], createdAtEpoch: result.createdAtEpoch };
  }

  storeSummary(
    memorySessionId: string,

View on GitHub (pinned to d8bc9755e7)