Hmbown/CodeWhale · error · Error

Use a name between 1 and 200 characters.

Error message

Use a name between 1 and 200 characters.

What it means

The TraceStore rename() method validates the new name before performing the IndexedDB readwrite transaction: after trimming whitespace, the name must be 1-200 characters. It throws this plain Error to reject empty or oversized names rather than persisting an unusable label.

Solutions

  1. Trim the name and check 1 <= trimmed.length <= 200 before calling rename.
  2. Enforce a maxLength attribute or equivalent in the rename UI input.
  3. Show a validation message when the user submits an empty or >200-char name.

Example fix

// before
await store.rename(ref, userInput);
// after
const name = userInput.trim();
if (name.length === 0 || name.length > 200) throw new RangeError('name must be 1-200 chars');
await store.rename(ref, name);
Defensive patterns

Strategy: validation

Validate before calling

function isValidTraceName(name) { const t = String(name ?? '').trim(); return t.length >= 1 && t.length <= 200; }
if (!isValidTraceName(input)) showError('Use a name between 1 and 200 characters.');

Type guard

const isValidTraceName = (n: unknown): n is string => typeof n === 'string' && n.trim().length >= 1 && n.trim().length <= 200;

Prevention

When it happens

Trigger: Calling rename(savedReference, '') or a whitespace-only name (' '), or any name whose trimmed length exceeds 200, e.g. a clipboard paste of a long document title.

Common situations: Users clearing the rename input entirely or pasting long text; callers forgetting that trimming happens first so a 201-char name with spaces still fails.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/7afbb3837278f16f. Report an issue: GitHub.

Appendix: source

Thrown at pet/src/ui/storage.ts:107

  }
  private nextTime(previous?: string): string {
    const last = previous ? Date.parse(previous) : 0;
    return new Date(Math.max(Date.now(), Number.isFinite(last) ? last + 1 : 0)).toISOString();
  }
  async list(): Promise<SavedSummary[]> {
    return this.transaction('readonly', (_traces, metas, done) => {
      const req = metas.getAll();
      req.onsuccess = () => done((req.result as SavedSummary[]).sort((a, b) => b.savedAt.localeCompare(a.savedAt)));
    });
  }
  async getEntry(key: string): Promise<SavedTrace> {
    return this.transaction('readonly', (traces, _metas, done, fail) => {
      const req = traces.get(key); req.onsuccess = () => req.result ? done(req.result) : fail(missing());
    });
  }
  async get(key: string): Promise<Trace> { return (await this.getEntry(key)).trace; }
  async rename(expected: SavedReference, name: string): Promise<SavedReference> {
    const trimmed = name.trim(); if (!trimmed || trimmed.length > 200) throw new Error('Use a name between 1 and 200 characters.');
    return this.transaction('readwrite', (traces, metas, done, fail) => {
      const req = traces.get(expected.key);
      req.onsuccess = () => {
        try {
          if (!req.result) throw missing();
          const item: SavedTrace = req.result;
          if (item.savedAt !== expected.savedAt) throw changed();
          item.trace.name = trimmed; item.savedAt = this.nextTime(item.savedAt);
          traces.put(item); metas.put(summary(item)); done({ key: item.key, savedAt: item.savedAt });
        } catch (e) { fail(e as Error); }
      };
    });
  }
  async delete(expected: SavedReference): Promise<void> {
    await this.transaction<void>('readwrite', (traces, metas, done, fail) => {
      const req = traces.get(expected.key);
      req.onsuccess = () => {
        if (req.result && req.result.savedAt !== expected.savedAt) { fail(changed()); return; }

View on GitHub (pinned to 433685b202)