createLogger: invalid logger string (e.g. typo'd 'VERBOSE') silently passes through and crashes with 'logger.state is not a function'

Open Beginner friendly
#40 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
typescript
Domain
cli

Research direction

Start in src/loggers.ts at createLogger and review the existing tests in src/test/loggers.test.ts. Run those logger tests first, then cover unknown and empty string values using the issue's preferred validation behavior. Done means invalid logger strings produce a clear error while the existing verbose, omitted, and Logger-object cases remain valid.

Written by the indexing model from the issue text.

Description

bug S3

Severity

S3. Reasonable users hit this by writing \"logger\": \"VERBOSE\" (or any string other than the exact lowercase verbose) in their JSON config. The failure is loud but the error is opaque and doesn't mention the offending field, so debugging starts in the wrong place.

Observed behavior

createLogger in src/loggers.ts performs a single equality check against the string 'verbose', then falls back to a nullish-coalescing default:

export function createLogger(loggerSpec: LoggerSpec): Logger {
  if (loggerSpec === 'verbose') {
    return new VerboseLogger(true);
  }
  return loggerSpec ?? new VerboseLogger(false);
}

Any value that is neither the literal 'verbose' nor nullish is returned unchanged and the loop then treats it as a Logger. Because TypeScript believes the return type is Logger, the first method call on the result crashes with a TypeError.

Reproduced via the CLI with a minimal config:

{
  \"name\": \"test\",
  \"agent\": [\"test\", { \"responses\": [{ \"status\": \"success\", \"output\": \"ok\" }] }],
  \"promptGenerator\": [\"test\", { \"prompts\": [\"hello\"] }],
  \"logger\": \"VERBOSE\",
  \"maxPrompts\": 1,
  \"interPromptPause\": 0
}
$ node dist/cli.js bad-config.json
logger.state is not a function

The same happens for any other invalid value that survives the ?? operator: \"Verbose\", \"verbose \", \"quiet\", \"\" (empty string), true, 0, etc. Programmatic callers can only hit this via as any casts, but JSON config users hit it directly because loadCliConfig parses with JSON.parse(raw) as LoopCliConfig and does no runtime validation.

The JSON schema at schema/loop-the-loop.schema.json declares \"logger\": { \"enum\": [\"verbose\"] }, but loadCliConfig does not run schema validation, and none of the bundled examples set logger in their config (users typically reach for --verbose), so the schema does not protect the runtime path.

Expected behavior

createLogger should either:

  1. Throw a clear error when handed an unrecognised string (e.g. Invalid logger value 'VERBOSE': expected 'verbose' or omit the field), or
  2. Silently treat unknown values as 'quiet' (return a disabled VerboseLogger).

Option 1 is more in keeping with the project's other input-validation helpers (parseArgs, assertTestTaskConfig, etc.) and matches the spirit of issues like #23, #24 and #33 where silent coercion was rejected.

Minimal reproduction

import { createLogger } from 'loop-the-loop/loggers';

const log = createLogger('VERBOSE' as any);
log.state('hi'); // TypeError: log.state is not a function

Or via the CLI as shown above with a config whose \"logger\" field is anything other than the exact string \"verbose\".

Suggested fix

export function createLogger(loggerSpec: LoggerSpec): Logger {
  if (loggerSpec === undefined) {
    return new VerboseLogger(false);
  }
  if (loggerSpec === 'verbose') {
    return new VerboseLogger(true);
  }
  if (typeof loggerSpec === 'string') {
    throw new Error(
      \`Invalid logger value '\${loggerSpec}': expected 'verbose' or omit the field.\`,
    );
  }
  return loggerSpec;
}

Add tests for the new branch (unknown string throws, empty string throws) alongside the existing createLogger tests in src/test/loggers.test.ts.

Dominant language
TypeScript
Stars
2
Forks
1
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from joewalker/loop-the-loop

All issues in joewalker/loop-the-loop

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.