{"record":{"id":"daef744cce3f34ae","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"skill-cos-required","errorCode":"SKILL_COS_REQUIRED","errorMessage":"contentBackend=cos required but COS credentials missing (secretId / secretKey / bucket). Verify Shark COS config or cos.env in service mode — refusing to silently fall back to local fs.","messagePattern":"contentBackend=cos required but COS credentials missing \\(secretId / secretKey / bucket\\)\\. Verify Shark COS config or cos\\.env in service mode — refusing to silently fall back to local fs\\.","errorType":"error_code","errorClass":"SkillCoreError","httpStatus":null,"severity":"critical","filePath":"MemoryCore/src/core/skill/skill-config.ts","lineNumber":99,"sourceCode":"      from: \"tcvdb\",\n      to: \"sqlite\",\n      reason: \"TCVDB credentials missing (url / apiKey / database)\",\n      level: \"warn\",\n    });\n    logger.warn(\n      `${TAG} storeBackend=tcvdb requested but credentials missing — degrading to sqlite`,\n    );\n    storeBackend = \"sqlite\";\n  }\n\n  // --------------- content ---------------\n  const explicitContent = input.contentBackend;\n  let contentBackend: \"local\" | \"cos\";\n  if (explicitContent === \"cos\") {\n    if (probe.hasCosCredentials) {\n      contentBackend = \"cos\";\n    } else if (strictMode) {\n      throw new SkillCoreError(\n        \"SKILL_COS_REQUIRED\",\n        \"contentBackend=cos required but COS credentials missing (secretId / secretKey / bucket). \" +\n          \"Verify Shark COS config or cos.env in service mode — refusing to silently fall back to local fs.\",\n      );\n    } else {\n      degradations.push({\n        field: \"contentBackend\",\n        from: \"cos\",\n        to: \"local\",\n        reason: \"COS credentials missing (secretId / secretKey / bucket)\",\n        level: \"info\",\n      });\n      logger.info(\n        `${TAG} contentBackend=cos requested but credentials missing — degrading to local fs`,\n      );\n      contentBackend = \"local\";\n    }\n  } else if (explicitContent === \"local\") {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/skill/skill-config.ts#L81-L117","documentation":"resolveSkillConfig enforces that when contentBackend is explicitly set to \"cos\" (Tencent Shark COS object storage), COS credentials (secretId, secretKey, bucket) must actually be present. In strict mode, instead of silently degrading to the local filesystem, it throws SkillCoreError with code SKILL_COS_REQUIRED so misconfiguration is surfaced immediately.","triggerScenarios":"Calling resolveSkillConfig (directly or via resolved()) with input.contentBackend = \"cos\" while the probed credential set (hasCosCredentials) is empty — secretId/secretKey/bucket not loaded from Shark COS config or cos.env in service mode, and strictMode is enabled.","commonSituations":"Deploying to an environment where cos.env is missing or not mounted; typos in env var names (COS_SECRET_ID etc.); credentials loaded after config resolution; copy-pasting a config with contentBackend:\"cos\" from another service that had the creds; CI runs without secret injection.","solutions":["Provide the COS credentials via Shark COS config or cos.env in service mode (secretId, secretKey, bucket) and restart","Verify the env file is actually mounted/loaded before resolveSkillConfig runs (check load order and path)","Fix credential env var names/typos and confirm probe.hasCosCredentials becomes true (log it)","If COS is not actually required, remove contentBackend:\"cos\" so config falls back to local with a recorded degradation"],"exampleFix":"// before: cos required but creds never loaded\nconst config = resolveSkillConfig({ contentBackend: \"cos\", strictMode: true });\n// after: load creds first\nimport { loadCosEnv } from \"./cos-env\";\nloadCosEnv(\"/etc/secrets/cos.env\");\nconst config = resolveSkillConfig({ contentBackend: \"cos\", strictMode: true });","handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from \"fs\";\nfunction hasCosCreds(envPath = \"/etc/secrets/cos.env\"): boolean {\n  const id = process.env.COS_SECRET_ID, key = process.env.COS_SECRET_KEY,\n        bucket = process.env.COS_BUCKET;\n  if (id && key && bucket) return true;\n  if (existsSync(envPath)) {\n    const txt = readFileSync(envPath, \"utf8\");\n    return /COS_SECRET_ID=.+/.test(txt) && /COS_SECRET_KEY=.+/.test(txt) && /COS_BUCKET=.+/.test(txt);\n  }\n  return false;\n}\nif (wantCos && !hasCosCreds()) throw new Error(\"COS requested but credentials missing\");","typeGuard":"function cosCredsPresent(c: { secretId?: string; secretKey?: string; bucket?: string }):\n  c is { secretId: string; secretKey: string; bucket: string } {\n  return Boolean(c.secretId && c.secretKey && c.bucket);\n}","tryCatchPattern":"try {\n  config = resolveSkillConfig({ contentBackend: \"cos\", strictMode: true });\n} catch (e) {\n  if (e instanceof SkillCoreError && e.code === \"SKILL_COS_REQUIRED\") {\n    logger.error(\"COS backend requested but credentials missing; check cos.env / Shark config\");\n    process.exit(1); // or reconfigure to local backend\n  }\n  throw e;\n}","preventionTips":["Mount and load cos.env before config resolution in service mode","Verify secretId/secretKey/bucket env vars exist in every deploy environment (CI, staging, prod)","Run a startup preflight that probes hasCosCredentials when contentBackend=cos","Do not set contentBackend:\"cos\" by default in shared config templates"],"tags":["configuration","object-storage","cos","missing-credentials","strict-mode"],"backgroundTag":"missing-env-var","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}