@motioneffector/flags

Documentation

Errors API

Error classes thrown by the flag store.


FlagsError

Base error class for all library errors.

class FlagsError extends Error {
  name: 'FlagsError'
}

All errors from this library extend FlagsError, so you can catch them all:

import { FlagsError } from '@motioneffector/flags'

try {
  store.check('invalid syntax ((')
} catch (e) {
  if (e instanceof FlagsError) {
    console.log('Flag store error:', e.message)
  }
}

ValidationError

Thrown when a flag key or value fails validation.

class ValidationError extends FlagsError {
  name: 'ValidationError'
  field?: string
}
Property Type Description
message string Description of the validation failure
field string | undefined The field that failed validation (if applicable)

When Thrown

Invalid key:

store.set('', 'value')
// ValidationError: Flag key cannot be empty

store.set('has spaces', 'value')
// ValidationError: Flag key cannot contain spaces

store.set('AND', 'value')
// ValidationError: Flag key cannot be a reserved word

store.set('OR', 'value')
// ValidationError: Flag key cannot be a reserved word

store.set('NOT', 'value')
// ValidationError: Flag key cannot be a reserved word

Invalid value type:

store.set('key', { object: true })
// TypeError: Flag value must be boolean, number, or string

store.set('key', [1, 2, 3])
// TypeError: Flag value must be boolean, number, or string

Type mismatch in operations:

store.set('name', 'Alice')
store.toggle('name')
// TypeError: Cannot toggle non-boolean flag

store.increment('name')
// TypeError: Cannot increment non-numeric flag

ParseError

Thrown when a condition expression has invalid syntax.

class ParseError extends FlagsError {
  name: 'ParseError'
  position?: number
  input?: string
}
Property Type Description
message string Description of the parse error
position number | undefined Character position where the error occurred
input string | undefined The input string that failed to parse

When Thrown

Empty condition:

store.check('')
// ParseError: Condition cannot be empty

store.check('   ')
// ParseError: Condition cannot be empty

Incomplete expression:

store.check('a AND')
// ParseError: Unexpected end of expression

store.check('AND b')
// ParseError: Unexpected token 'AND'

store.check('a ==')
// ParseError: Expected value after operator

Unbalanced parentheses:

store.check('(a AND b')
// ParseError: Unclosed parenthesis

store.check('a AND b)')
// ParseError: Unexpected closing parenthesis

store.check('()')
// ParseError: Empty parentheses

Invalid operators:

store.check('a >> 5')
// ParseError: Invalid operator '>>'

store.check('a === 5')
// ParseError: Invalid operator '==='

String ordering:

store.check('name > "alice"')
// ParseError: Ordering operators not supported for strings

Error Handling Patterns

Catching All Library Errors

import { FlagsError, ValidationError, ParseError } from '@motioneffector/flags'

try {
  store.set(userInput.key, userInput.value)
  store.check(userInput.condition)
} catch (e) {
  if (e instanceof ValidationError) {
    console.error('Invalid input:', e.message)
  } else if (e instanceof ParseError) {
    console.error('Invalid condition:', e.message)
  } else if (e instanceof FlagsError) {
    console.error('Store error:', e.message)
  } else {
    throw e  // Re-throw unknown errors
  }
}

Validating User Input

function isValidCondition(condition: string): boolean {
  try {
    store.check(condition)
    return true
  } catch (e) {
    if (e instanceof ParseError) {
      return false
    }
    throw e
  }
}

Graceful Degradation

function safeCheck(condition: string, fallback = false): boolean {
  try {
    return store.check(condition)
  } catch (e) {
    console.warn('Invalid condition:', condition, e)
    return fallback
  }
}

Errors That Are NOT Thrown

Some error conditions are handled gracefully without throwing:

Storage Errors

// Storage failures are logged, not thrown
const store = createFlagStore({
  persist: { storage: failingStorage }
})
// Works in-memory, logs error to console.error

Missing Flags

// Missing flags return undefined, not an error
store.get('nonexistent')  // undefined

// In conditions, missing flags are 0/falsy
store.check('missing')  // false (no error)

Subscriber Errors

// Errors in subscribers are caught and logged
store.subscribe(() => { throw new Error('Oops') })
store.set('x', 1)  // Still works, error logged to console.error

Compute Function Errors

// Errors in compute functions are caught
store.compute('result', ['x'], () => { throw new Error('Oops') })
store.get('result')  // Returns previous value, error logged