{"record":{"id":"a046ed5e1262c284","repo":"hyperledger/fabric","slug":"chaincode-s-attempted-to-write-to-the-namespace-o-a046ed","errorCode":null,"errorMessage":"chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked","messagePattern":"chaincode (.+?) attempted to write to the namespace of a system chaincode that cannot be invoked","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/committer/txvalidator/v14/vscc_validator.go","lineNumber":188,"sourceCode":"\t\t// 1) we don't write to LSCC - an application chaincode is free to invoke LSCC\n\t\t//    for instance to get information about itself or another chaincode; however\n\t\t//    these legitimate invocations only ready from LSCC's namespace; currently\n\t\t//    only two functions of LSCC write to its namespace: deploy and upgrade and\n\t\t//    neither should be used by an application chaincode\n\t\tif writesToLSCC {\n\t\t\treturn peer.TxValidationCode_ILLEGAL_WRITESET,\n\t\t\t\terrors.Errorf(\"chaincode %s attempted to write to the namespace of LSCC\", ccID)\n\t\t}\n\t\t// 2) we don't write to the namespace of a chaincode that we cannot invoke - if\n\t\t//    the chaincode cannot be invoked in the first place, there's no legitimate\n\t\t//    way in which a transaction has a write set that writes to it; additionally\n\t\t//    we don't have any means of verifying whether the transaction had the rights\n\t\t//    to perform that write operation because in v1, system chaincodes do not have\n\t\t//    any endorsement policies to speak of. So if the chaincode can't be invoked\n\t\t//    it can't be written to by an invocation of an application chaincode\n\t\tif writesToNonInvokableSCC {\n\t\t\treturn peer.TxValidationCode_ILLEGAL_WRITESET,\n\t\t\t\terrors.Errorf(\"chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked\", ccID)\n\t\t}\n\n\t\t// validate *EACH* read write set according to its chaincode's endorsement policy\n\t\tfor _, ns := range wrNamespace {\n\t\t\t// Get latest chaincode version, vscc and validate policy\n\t\t\ttxcc, vscc, policy, err := v.GetInfoForValidate(chdr, ns)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Errorf(\"GetInfoForValidate for txId = %s returned error: %+v\", chdr.TxId, err)\n\t\t\t\treturn peer.TxValidationCode_INVALID_OTHER_REASON, err\n\t\t\t}\n\n\t\t\t// if the namespace corresponds to the cc that was originally\n\t\t\t// invoked, we check that the version of the cc that was\n\t\t\t// invoked corresponds to the version that lscc has returned\n\t\t\tif ns == ccID && txcc.ChaincodeVersion != ccVer {\n\t\t\t\terr = errors.Errorf(\"chaincode %s:%s/%s didn't match %s:%s/%s in lscc\", ccID, ccVer, chdr.ChannelId, txcc.ChaincodeName, txcc.ChaincodeVersion, chdr.ChannelId)\n\t\t\t\tlogger.Errorf(\"%+v\", err)\n\t\t\t\treturn peer.TxValidationCode_EXPIRED_CHAINCODE, err","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/committer/txvalidator/v14/vscc_validator.go#L170-L206","documentation":"This error is thrown by VSCC transaction validation when a transaction's write set attempts to modify the namespace of a system chaincode (SCC) that cannot be invoked by application chaincodes. Because system chaincodes have no endorsement policies, the validator cannot verify authorization for such writes, so it rejects the transaction outright with validation code ILLEGAL_WRITESET. This protects privileged state (e.g. lscc, qscc, cscc) from tampering via regular transactions.","triggerScenarios":"A committed transaction's read-write set (from VSCCValidateTx's write-set inspection) contains a write whose namespace matches a system chaincode name that is not invokable (writesToNonInvokableSCC is true). Typically produced by a chaincode that calls another chaincode targeting an SCC name, or a hand-crafted/malicious transaction.","commonSituations":"Application chaincode accidentally invoking a system chaincode name (e.g. 'lscc' or a custom SCC); malicious or corrupted transaction payloads submitted to the network; chaincode code constructing rwset keys that collide with SCC namespaces.","solutions":["Identify the chaincode producing the write (logged by ccID/txId in peer logs) and remove any calls or state writes targeting system chaincode namespaces","Ensure application chaincode only writes to its own namespace and invokes other chaincodes via the proper QSCC/invocation APIs, never by writing their keys directly","If a custom system chaincode must be written to, mark it as invokable or adjust its registration so writes are permitted","Investigate the transaction origin; if unexpected, treat as a security event and validate client SDK usage"],"exampleFix":"// before (chaincode writes into lscc namespace)\nstub.PutState(\"lscc\", someBytes)\n// after\nstub.PutState(\"mykey\", someBytes) // write only within your own chaincode namespace","handlingStrategy":"validation","validationCode":"// chaincode-side check before writing\nif (keyOrNamespace.startsWith('lscc') || keyOrNamespace.startsWith('qscc') || keyOrNamespace.startsWith('cscc') || keyOrNamespace.startsWith('vscc')) {\n  throw new Error('cannot write to system chaincode namespace');\n}","typeGuard":"function isSystemChaincodeNamespace(ns) {\n  return ['lscc','qscc','cscc','vscc','escc','nvcc'].includes(ns);\n}","tryCatchPattern":null,"preventionTips":["Never PutState/DelState keys in system chaincode namespaces","Only invoke SCCs through their supported APIs (qscc queries, cscc config)"],"tags":["hyperledger-fabric","chaincode","tx-validation","illegal-writeset","system-chaincode"],"backgroundTag":"illegal-writeset","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}