Hmbown/CodeWhale · error · Error

Thread summary returned HTTP ${response.statusCode}.

Error message

Thread summary returned HTTP ${response.statusCode}.

What it means

After the staged manifest validates, its [plugin].name is checked by validate_skill_name_segment because that name becomes the installation directory under the user plugins dir. The name is rejected when empty, whitespace-padded or containing any whitespace, equal to '.' or '..', containing '/' or '\\', or otherwise not a single normal path component. This is the staged-time twin of the plugin_target_path guard, failing before any copy happens.

Source

Thrown at extensions/vscode/src/runtime.ts:119

    version,
  };
}

export async function listThreadSummaries(
  config: RuntimeConfig,
  limit = 8,
): Promise<ThreadSummary[]> {
  const baseUrl = runtimeBaseUrl(config);
  const response = await requestJson(
    `${baseUrl}/v1/threads/summary?limit=${encodeURIComponent(String(limit))}`,
    config.token,
  );

  if (response.statusCode === 401) {
    throw new Error("Thread summaries require the runtime bearer token.");
  }
  if (response.statusCode !== 200) {
    throw new Error(`Thread summary returned HTTP ${response.statusCode}.`);
  }

  return readThreadSummaries(response.body);
}

export async function listSnapshots(config: RuntimeConfig, limit = 8): Promise<SnapshotEntry[]> {
  const baseUrl = runtimeBaseUrl(config);
  const response = await requestJson(
    `${baseUrl}/v1/snapshots?limit=${encodeURIComponent(String(limit))}`,
    config.token,
  );

  if (response.statusCode === 401) {
    throw new Error("Restore points require the runtime bearer token.");
  }
  if (response.statusCode !== 200) {
    throw new Error(`Restore points returned HTTP ${response.statusCode}.`);
  }

View on GitHub (pinned to 8880682c63)

Solutions

  1. Set [plugin].name to a single path-safe slug: no whitespace, no separators, not '.'/'..' (e.g. "data-sync").
  2. Use a description/title field for the human-readable name and keep the name field machine-safe.
  3. Lint manifests before publishing: reject names that trim unevenly or contain path characters.

Example fix

// before (plugin.json)
{ "plugin": { "name": "Data Sync Plugin" } }

// after
{ "plugin": { "name": "data-sync", "description": "Data Sync Plugin" } }
Defensive patterns

Strategy: validation

Validate before calling

let name = validated.manifest.plugin.name.clone();
if !is_safe_plugin_name(&name) {
    anyhow::bail!("[plugin].name must be one path-safe segment, got '{name}'");
}

Type guard

fn is_safe_plugin_name(name: &str) -> bool {
    !name.is_empty()
        && name.trim() == name
        && !name.chars().any(char::is_whitespace)
        && !matches!(name, "." | "..")
        && !name.contains('/') && !name.contains('\\')
}

Try / catch

match validate_staged(&staged_path) {
    Ok(v) => v,
    Err(e) if e.to_string().contains("[plugin].name is not a safe directory name") =>
        return Err(e).context("rename the plugin in its manifest to a slug and reinstall"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The staged bundle's plugin.json has a name like "Data Sync", "tools/exporter", "..", or an empty string; validate_staged extracts the name and the segment check fails.

Common situations: Authors putting display names into [plugin].name; copy-pasting a name with a trailing newline or space; third-party bundles authored against looser conventions; names containing Windows separators.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/424af30458bf2f60. Report an issue: GitHub.