sickn33/agentic-awesome-skills · error · Error

Invalid JSON

Error message

Invalid JSON: ${error}

What it means

In the fp-refactor skill's before-code, parseJSON catches JSON.parse's SyntaxError and re-wraps it with the 'Invalid JSON' prefix. It fires whenever the input string is not well-formed JSON — the skill uses it to motivate error-as-value refactoring.

Solutions

  1. Log the offending substring around the parse position to find the malformed token
  2. If APIs may return HTML error pages, check content-type before parsing
  3. Return E.Either<Error, unknown> from parseJSON instead of throwing (the skill's refactor direction)

Example fix

// before
try { return JSON.parse(input) } catch (e) { throw new Error(`Invalid JSON: ${e}`) }

// after
const parseJSON = (input: string): E.Either<Error, unknown> =>
  E.tryCatch(() => JSON.parse(input), E.toError)
Defensive patterns

Strategy: validation

Validate before calling

const looksLikeJson = (s: string) => /^\s*[\[\{"\d-tnf]/.test(s)

Try / catch

try {
  JSON.parse(input)
} catch (e) {
  // e is SyntaxError with position info; log input around e.message
}

Prevention

When it happens

Trigger: Calling parseJSON with truncated payloads, single quotes, trailing commas, unquoted keys, plain text/HTML error pages from an API, or an empty string.

Common situations: APIs returning HTML error pages with 200 status; truncated responses from cut connections; log lines with JSON-ish prefixes; hand-built strings missing quotes.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of sickn33/agentic-awesome-skills@58d857988f (2026-08-26). Data as JSON: /api/errors/398c6914018a850d. Report an issue: GitHub.

Appendix: source

Thrown at skills/fp-refactor/SKILL.md:62

### The Problem with try-catch

Traditional try-catch blocks have several issues:
- Error handling is implicit and easy to forget
- The type system doesn't track which functions can throw
- Control flow is non-linear and harder to reason about
- Composing multiple fallible operations is verbose

### Pattern: Synchronous try-catch to Either

#### Before (Imperative)

```typescript
function parseJSON(input: string): unknown {
  try {
    return JSON.parse(input);
  } catch (error) {
    throw new Error(`Invalid JSON: ${error}`);
  }
}

function validateUser(data: unknown): User {
  try {
    if (!data || typeof data !== 'object') {
      throw new Error('Data must be an object');
    }
    const obj = data as Record<string, unknown>;
    if (typeof obj.name !== 'string') {
      throw new Error('Name is required');
    }
    if (typeof obj.age !== 'number') {
      throw new Error('Age must be a number');
    }
    return { name: obj.name, age: obj.age };
  } catch (error) {
    throw error;

View on GitHub (pinned to 58d857988f)