affaan-m/ECC · error · Error
must be a non-empty string
Error message
${label} must be a non-empty string What it means
ensureString is a shared guard in the observations telemetry module: the value must be a string whose trimmed length is non-zero, otherwise the error is thrown with the parameter label embedded. It returns the trimmed value. It is used to validate identifiers like task and skillId before writing observation records.
Solutions
- Provide a non-empty string for the flagged field (see label in the message)
- Trim and check the value before calling: if (!value || !value.trim()) handle it upstream
- Fix the config/CLI plumbing so the field is actually populated
- If the field is genuinely optional, pass a sensible default like 'unknown' instead of an empty string
Example fix
// before
recordObservation({ task: cfg.taskName ?? '', skillId }); // throws when unset
// after
const task = (cfg.taskName ?? '').trim();
if (!task) throw new Error('taskName is required in config');
recordObservation({ task, skillId }); Defensive patterns
Strategy: type-guard
Validate before calling
function isNonEmptyString(v) {
return typeof v === 'string' && v.trim().length > 0;
}
if (!isNonEmptyString(task) || !isNonEmptyString(skillId)) {
throw new Error('task and skillId are required non-empty strings');
} Type guard
const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;
Try / catch
try {
recordObservation({ task, skillId });
} catch (err) {
if (err.message.endsWith('must be a non-empty string')) {
console.warn(`Skipping observation: ${err.message}`);
return null;
} throw err;
} Prevention
- Validate CLI flags and config fields for emptiness at program start
- Never use '' as a default for required identifiers — leave undefined and fail early
- Trim values read from env vars and config files before use
- Add schema validation (e.g. zod) for telemetry inputs
When it happens
Trigger: Calling observation APIs with task or skillId set to undefined, null, an empty string, or a whitespace-only string like ' '; also passing a non-string (number, object) which fails the typeof check.
Common situations: Optional config field left unset so the value stays undefined; template-literal interpolation producing '' when an upstream variable is empty; extracting task names from a CLI flag the user never supplied; refactors changing a field name so the old variable no longer exists.
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
- -32602
- a claim token is required
- a confirmed nonempty coordinate is required
- a generated candidate cannot claim original-source identity
- A managed install plan with operations is required.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/6e5fa0714e1cbd77.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/skill-improvement/observations.js:23
const os = require('os');
const OBSERVATION_SCHEMA_VERSION = 'ecc.skill-observation.v1';
function resolveProjectRoot(options = {}) {
return path.resolve(options.projectRoot || options.cwd || process.cwd());
}
function getSkillTelemetryRoot(options = {}) {
return path.join(resolveProjectRoot(options), '.claude', 'ecc', 'skills');
}
function getSkillObservationsPath(options = {}) {
return path.join(getSkillTelemetryRoot(options), 'observations.jsonl');
}
function ensureString(value, label) {
if (typeof value !== 'string' || value.trim().length === 0) {
throw new Error(`${label} must be a non-empty string`);
}
return value.trim();
}
function createObservationId() {
return `obs-${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2, 8)}`;
}
function createSkillObservation(input) {
const task = ensureString(input.task, 'task');
const skillId = ensureString(input.skill && input.skill.id, 'skill.id');
const skillPath = typeof input.skill.path === 'string' && input.skill.path.trim().length > 0
? input.skill.path.trim()
: null;
const success = Boolean(input.success);
const error = input.error === null || input.error === undefined ? null : String(input.error);
const feedback = input.feedback === null || input.feedback === undefined ? null : String(input.feedback);View on GitHub (pinned to 8321021c54)